Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Annotation Warmer Laravel Package

happyr/annotation-warmer

Warms up PHP annotation caches ahead of runtime so your first request doesn't pay the parsing cost. Scans classes for annotations, primes the reader cache, and exposes an Artisan command, making it a small performance add-on for Laravel and Doctrine-based apps.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose Symfony bundle whose job is to pre-populate Doctrine's annotation reader cache. Instead of paying the annotation-parsing cost on the first web request after a deploy, you run the warmer during cache:warmup and the PHP file cache is already populated.

The package's last meaningful release was 0.3.0, and it has essentially no adoption, so treat the README and the source as the source of truth for exact class and config names rather than any blog post or assumption.

Heads-up on 0.3.0: this release removed the default values for config and added service-definition guards. Practically that means:

  • You can no longer rely on the bundle "just working" with an empty config block. You must explicitly declare the config tree (directories/bundles to scan) or the bundle will either fail container compilation or silently warm nothing.
  • The bundle now checks whether a service definition exists before using it, so it won't hard-crash when an optional service (custom annotation reader, cache pool, etc.) is absent — but it will also no-op quietly in that case.

Minimal path to a first working setup:

  1. Install it (expect to pin):

    composer require happyr/annotation-warmer
    

    The package predates modern Symfony Flex recipes, so it will very likely not be auto-registered. Add the bundle to config/bundles.php manually if it isn't there.

  2. Confirm the bundle class and config key. Look at the repository's src/ for the *Bundle class and DependencyInjection/Configuration.php. That file defines the exact config tree. On 0.3.0, pay attention to which nodes lost their defaults — those are now effectively required. Also skim tests/ — for small Happyr packages the tests are usually the most accurate usage documentation.

  3. Declare the config explicitly. Create config/packages/annotation_warmer.yaml (name per README) and list the directories you want scanned. Under 0.3.0 an empty or missing block is no longer safe.

  4. Point it at the code you care about. The first-use case is almost always "warm annotations for my entities (and optionally form types / validators / controllers)" so the first request after deploy doesn't stall on AnnotationReader::getClassAnnotations().

  5. Wire it into your deploy. Run bin/console cache:warmup --env=prod (or whatever dedicated command the bundle exposes) as part of your release step, after the cache has been cleared.

The first realistic win: a Symfony app with a large entity graph where the first request after cache:clear is noticeably slower. If your annotation cache is set to file/PhpFileCache, this bundle should collapse that cold-start penalty.

Implementation Patterns

Pair it with a file-based annotation cache. The warmer is only useful if your annotation reader actually persists to a cache you can pre-fill. In practice that means doctrine/annotations configured with PhpFileCache (or Symfony's framework.annotations.cache: file on older versions). If you use an in-memory or Redis-backed cache, a compile-time warmer either does nothing useful or writes to a cache the runtime never reads.

Configure directories, not individual classes. The natural config shape for this kind of bundle is a list of source directories (or a list of bundles) to scan. Prefer globbing over src/Entity and src/Form rather than enumerating classes — it survives refactors, and the warmer is cheap enough to over-scan.

Check the service wiring on 0.3.0. Because the release added hasDefinition()-style guards, the warmer only activates when the services it expects are registered under the names it looks for. If you use a custom Doctrine annotation reader service id, or you've replaced the default cache adapter, the warmer may compile fine and do nothing. Grep src/ for the service ids it checks before you assume it ran.

Standard deploy workflow:

# in your deploy script, prod env
bin/console cache:clear --no-warmup --env=prod
bin/console cache:warmup --env=prod          # warmer runs here

If the bundle exposes a dedicated command instead of riding on cache:warmup, run it explicitly between clear and the first request. Never run it against the dev cache and expect prod to benefit — the cache directories are separate.

Use it as a CI guard, secondarily. Running the warmer in CI on a clean cache is a cheap way to catch annotations that reference classes that no longer exist or have invalid import targets — failures that would otherwise only show up as a 500 on the first production request. Note that with the new service-definition guards, some "failures" now become silent skips, so assert on the output (cache file count) rather than exit code alone.

Verify the effect rather than trusting it. After warmup, inspect the annotation cache directory (commonly var/cache/prod/annotations/ for the PHP file cache) and confirm files were generated. Then hit a cold endpoint and compare timing with/without the warmer. If the directory is empty, the warmer isn't scanning what you think it is — or it skipped itself because its services weren't found.

Keep the scan scope aligned with runtime. Only warm classes that the runtime annotation reader will actually touch. Warming src/Command or src/MessageHandler classes that are never annotation-read is wasted deploy time and noisy cache.

Gotchas and Tips

  • 0.3.0 is a breaking change for existing users. If you configured the bundle with an empty config block or relied on implicit defaults (e.g., "scan src/"), you must now add explicit config on upgrade from 0.2.x. Check Configuration.php for which nodes became required, and pin 0.3.0 deliberately rather than floating.
  • Silent no-op risk from service guards. The new hasDefinition() checks make the bundle more defensive, but the failure mode moved from "fatal error at warmup" to "warmup succeeds and warms nothing." Always verify the annotation cache directory is populated after warmup; don't trust the green deploy.
  • It's effectively unmaintained. Last release 2019, two stars, zero dependents. Pin the version, and budget for replacing it. The functionality is small enough that a ~40-line custom CacheWarmerInterface implementation is a realistic exit path if the package breaks against a newer Symfony.
  • PHP 8 / Symfony 6.4+ deprecation of annotations. The entire premise (warming Doctrine annotations) is fading as the ecosystem moves to PHP attributes. If you're on modern Symfony, attributes are cached differently and this warmer may be irrelevant. Confirm your project still depends on doctrine/annotations before investing.
  • Cache target mismatch is a common failure mode. The warmer writes to wherever the annotation reader's cache is configured at warmup time. If prod and dev use different cache adapters/paths, or if the warmer's own config assumes a default path (now that defaults are gone, this is more explicit but easier to get wrong), you'll warm into a directory the runtime never reads. Cross-check both configs.
  • Permissions and directories. A warmup run as a different user (e.g., root in a container build vs. www-data at runtime) can leave cache files unreadable. Make sure the writable cache dir is owned consistently.
  • Cold-start is the only benefit. This does nothing for steady-state performance. Don't reach for it to fix slow requests that are actually N+1 queries or a missing index.
  • Dynamic/generated classes won't be caught. Anything created at runtime (proxies, generated form types, container-built classes) isn't on disk when the warmer scans, so it can't be pre-warmed. Expect a residual cold path for those.
  • Debugging: clear cache first (cache:clear --no-warmup), then run warmup with -vvv. If the bundle has a scan command, run it and check it reports the classes you expect. Compare the annotation cache file count before/after. On 0.3.0, also dump the container (bin/console debug:container | grep -i annotation) to confirm the warmer service and its dependencies are registered.
  • Extension point: if the bundle's scanning is too coarse, or if the new service guards keep it from activating against your custom reader/cache wiring, the cleanest extension is to stop using it and register your own cache warmer that iterates Finder results and calls getClassAnnotations() / getMethodAnnotations() on each — same effect, full control over scope, service wiring, and error handling.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings