Backend performance best practices

🐇

Fast backends stay fast under load.

Backend performance decides how long the first byte takes and how many visitors the PHP processes can serve at once. Most of it is design: caching, short requests, work moved to the background.

Time to first byte

The time to first byte (TTFB) is mostly PHP time: how long the code needs to build the response. Each request holds one PHP process for that time, so a faster response also means more visitors at once. See monitoring for how to measure it.

Cache early

Put caching behind an abstraction from the start, so the store can change later without touching the calling code. Options on fortrabbit:

StoreUse
FilesSimple, the default of most CMS. Slower than memory, and it fills the storage
DatabaseShared by all PHP processes, good for data that stays valid for a long time
APCuIn-memory cache inside PHP, turned on in the PHP settings. Not shared with jobs or SSH
Full-page cacheThe fastest: the CMS or a CDN serves the finished HTML without running PHP

OPcache works on its own and caches compiled PHP code, not application data.

Reduce I/O

  • Includes: Load only the classes a request needs. Composer's optimized autoloader, composer install --optimize-autoloader, cuts file lookups.
  • File sessions and caches: Move them to the database where the access pattern allows it.
  • OPcache timestamps: With opcache.validate_timestamps=0, PHP stops checking .php files for changes. Changed files then need an OPcache reset to apply.

Keep OPcache below full

The OPcache metric shows how full the OPcache memory is. It fills up after a deployment, then stays flat. The fill level depends on the amount of PHP code, including vendor/, not on the number of visitors. At 100%, files that do not fit are compiled again on every request. Remove unused Composer packages and CMS plugins, then deploy again.

Move slow work to the background

Image transforms, video encoding, mass mail, imports and exports do not belong in a web request. Run them in jobs or hand them to an external service. Make every external service easy to switch off: the shop keeps running when the image service fails.

Keep max_execution_time low, so one slow request cannot block a PHP process for long. See PHP processes and max execution time.

Plan for a CDN

A CDN serves images, CSS and JS from its own network, so those requests never reach the environment. Set long cache headers for static files from the start, see HTTP headers. Some CDNs work best with a separate hostname for assets, such as assets.example.com; plan the URLs early when that is the goal.

Profile and load test

Applications are fast at launch and slow down as data and features grow. A profiler shows where a request spends its time: Blackfire runs on fortrabbit. A load test with a tool such as k6 or ab shows at which number of parallel requests the site breaks, before real visitors find out.

Limit bots

Crawlers can cause most of the load. A navigation or filter plugin can lead a bot through an endless number of almost identical pages, each one rendered and cached. Turn on the incoming firewall (WAF), block abusive IPs in .htaccess, and keep filter URLs out of crawling with robots.txt or nofollow.

Written by a human. Review, grammar checks and typo fixes by AI.

AI use & editorial processEdit on GitHub ↗