In Composer, what does composer dump-autoload -o change about how classes are found, and why is it for production rather than development?
answer
- PSR-4 rules converted into a classmap
- known classes: no filesystem check
- misses still fall back to PSR-4
- config optimize-autoloader
- --strict-psr fails on mapping errors
basics
~20 sdump-autoload -o scans PSR-4 and PSR-0 directories and writes every class into the classmap, so known classes resolve by array lookup, not a filesystem check. It suits production, where code changes only at deploy, not development.
solid answer
~50 sBy default a PSR-4 rule is resolved at runtime: the loader builds a candidate path and checks whether the file exists, which costs filesystem calls for every first use of a class. `composer dump-autoload -o` (`--optimize`), or `install`/`update` with `-o`, or `"optimize-autoloader": true` in `config`, **converts PSR-4/PSR-0 rules into classmap entries** at dump time. A known class then resolves by one array lookup, and with OPcache the classmap array itself is cached. Composer's docs call it a production default with no real trade-off. Two limits: it does not record **misses**, so a lookup for a class that does not exist still falls back to PSR-4 filesystem checks; and in development, a class added after the dump is still found through that fallback, while the optimization only pays off once the map is rebuilt. `--strict-psr` on `dump-autoload`, or since 2.10 `--strict-psr-autoloader` on install/update, fails the build on PSR mapping errors.
code
bash · 8 lines# development: default
composer dump-autoload
# CI guard
composer dump-autoload -o --strict-psr --strict-ambiguous
# production build
composer install --no-dev -o --no-interactiongo deeper
Know that production builds run composer install --no-dev -o and development does not.
Explain the lookup order, how -o turns PSR-4 into a classmap, and why misses still hit the filesystem.
Add --strict-psr checks to CI, measure the autoloader's share of request time, and decide whether a Level 2 option is justified.
Standardize the production build flags across services so autoloader behaviour is identical everywhere and not a per-team choice.
## How the default autoloader finds a class Composer's `ClassLoader::findFile()` tries, in order: 1. the **classmap**, an in-memory array from class name to file path; 2. if the class is not there, the **PSR-4** (and legacy PSR-0) rules: build a candidate path from the prefix and check with the filesystem whether the file exists, trying each mapped directory in turn. With an unoptimized autoloader, your own code and most packages are only in step 2. Every first use of a class in a request costs one or more filesystem checks. In a large codebase that loads hundreds of classes per request, Composer's own documentation estimates the autoloader's cost at 50-100 ms per request in large frameworks that use many classes. ## What `-o` does `--optimize` makes Composer **scan every PSR-4 and PSR-0 directory at dump time** and write every class it finds into `vendor/composer/autoload_classmap.php`. At runtime, those classes are resolved in step 1 by an array lookup, with no filesystem access. Because the classmap is a plain PHP file returning an array, OPcache keeps it compiled in memory, so loading it is nearly free. You can turn it on three ways: - `composer dump-autoload -o` (or `--optimize`) - `composer install -o` / `composer update -o` (`--optimize-autoloader`) - `"config": {"optimize-autoloader": true}` in `composer.json`, which applies it to every dump Composer's autoloader-optimization guide calls this "Level 1" and says it should always be enabled in production. ## What it does not do - **Misses are not cached.** If code calls `class_exists('Some\Missing')`, the classmap has no entry and the loader falls through to the PSR-4 filesystem checks, every time. Two "Level 2" options, an authoritative classmap or an APCu cache, address that at a price. - **The map is a snapshot.** A class created after the dump is not in the map. With `-o` alone it is still found through the PSR-4 fallback, only more slowly; with an authoritative classmap it is not found at all. ## Why not in development Composer's guide says plainly that none of the optimizations should be enabled in development. The snapshot is out of date as soon as you add, rename or move a class; `-o` keeps working through the fallback, so the benefit simply evaporates, while the stricter levels break outright. A dump is quick but not instant on a large codebase, so rebuilding after every file change is friction for no gain. | Environment | Recommended | |---|---| | development | default dump (`composer dump-autoload`) | | CI running tests | default, or `-o` to match production | | production build | `composer install --no-dev -o` (or stricter, see Level 2) | ## Making it part of the build In practice the optimization belongs to the production build step, next to the dependency install: 1. `composer install --no-dev -o --no-interaction` in the image build or deploy script; 2. or `composer install --no-dev` followed by `composer dump-autoload --no-dev -o`, useful when the build generates classes (for example compiled containers or proxies) between the two steps, so the dump sees them; 3. never on a shared development machine, where the map would be stale after the next edit. Because `dump-autoload` infers dev mode from the last install, passing `--no-dev` explicitly avoids surprises when the two commands run in different contexts. ## Catching mapping errors while you optimize Scanning directories reveals classes whose file path does not match their namespace, which PSR-4 would never find at runtime. Composer reports these as PSR mapping errors. To make them fail CI: 1. `composer dump-autoload -o --strict-psr` returns a non-zero exit code on PSR-4/PSR-0 mapping errors in your project (dependencies excluded). 2. `--strict-ambiguous` also fails when the same class is found in more than one file. 3. Since Composer 2.10, `install` and `update` accept `--strict-psr-autoloader` together with `--optimize-autoloader`, so the same guard can sit on the install step itself. These catch the classic "works on my Mac, fails on Linux" case-mismatch bug before it ships.
- After deploying with -o, a class generated at runtime into a PSR-4 directory still loads. Why, and would that change with -a?With `-o` alone, a class missing from the classmap falls through to the PSR-4 rules, which check the filesystem and find the new file. With `-a` (`--classmap-authoritative`) the loader treats the classmap as complete and returns not-found immediately, so that class would fail to autoload.
- Is there any reason not to enable optimize-autoloader in config for a production-only build?Composer's guide says Level 1 has no real trade-off in production: it only costs time at dump. The caution is about development machines, where the config key would also apply and the map would go stale; many teams therefore pass `-o` on the production install command instead of setting it in `config`.
The default loader is a librarian who walks to the shelf to check whether a book is there each time; -o hands her a printed catalogue made at opening time. Books on the catalogue are found instantly; a book added after printing still means a walk to the shelf.
saying these in an interview costs you the question
- -o makes the autoloader stop checking the filesystem for classes it does not know
- An optimized classmap should be enabled on every developer machine for speed
- -o caches missing classes so repeated class_exists calls are cheap
- dump-autoload -o changes which classes exist, not just how they are found
- PSR-4 mapping errors are silently ignored by --strict-psr