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

Composer Exclude Files Laravel Package

mcaskill/composer-exclude-files

Composer plugin that lets you exclude specific files from autoloading. Declare exclusions in composer.json to keep classmaps lean and stop unwanted files autoload entries from loading—handy for test fixtures, stubs, and optional integrations. Simple configuration, no code changes required.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install it as a real dependency, not a dev dependency. The plugin only does work during composer dump-autoload / composer install, and production deploys run with --no-dev, so it must survive that:

composer require mcaskill/composer-exclude-files

2. Allow the plugin (Composer 2.2+). Without this it is silently skipped and your exclusions do nothing:

composer config allow-plugins.mcaskill/composer-exclude-files true

This writes config.allow-plugins into composer.json — commit it so CI/Docker builds get the same behavior.

3. Audit what is being eagerly loaded. This is the first place to look. Composer's files autoload entries are required on every request, before Laravel even boots:

php -r "print_r(require 'vendor/composer/autoload_files.php');"

Cross-reference each entry with composer why <vendor/package>. On a typical Laravel app the usual suspects are symfony/polyfill-* bootstraps, symfony/deprecation-contracts/function.php, ralouphie/getallheaders, paragonie/random_compat, and the odd package shipping global helper functions you never call.

4. Add the exclusion block to your root composer.json (check the README for your pinned version — the key/format is extra.exclude-files with a list of vendor-relative paths/globs):

{
    "extra": {
        "exclude-files": [
            "vendor/symfony/polyfill-php80/bootstrap.php",
            "vendor/symfony/polyfill-php81/bootstrap.php"
        ]
    }
}

5. Regenerate and verify:

composer dump-autoload -vvv
php -r "print_r(require 'vendor/composer/autoload_files.php');"   # entries should be gone
php artisan about && vendor/bin/phpunit --testsuite=Feature

First use case: killing polyfill bootstraps for PHP versions your app no longer supports. It is a safe, measurable win — a handful of requires and function_exists guards removed from every request — and it validates the whole toolchain (plugin allowed, paths correct, dump-autoload wired into your deploy) before you try anything riskier.

Implementation Patterns

Audit → prune → measure loop. Treat this as a performance/cleanup task, not a config you set once. Script the baseline (autoload_files.php entry count, php -r timing of require vendor/autoload.php, or Blackfire/Telescope request timing), prune a batch, re-measure. Keep a note in the PR of why each file was excluded so the next developer doesn't re-add it.

Group exclusions by package with comments in your PR, not in JSON. composer.json doesn't support comments, so maintain a short docs/autoload-exclusions.md mapping each path → package → reason → date. This is the single most useful habit with this plugin, because exclusions are invisible at runtime.

Exact paths, not package names. The plugin strips entries from the generated autoload_files.php, so match the path as it appears in that file. Use globs only for families you control (e.g., every symfony/polyfill-php8* bootstrap) and prefer exact paths for one-offs so a package update that adds a new file doesn't silently get excluded too.

Resolve duplicate-symbol conflicts. The classic case: two packages ship a global function with the same name, and Composer's files autoloader fatals with "Cannot redeclare". Excluding one package's file is a legitimate fix — but then confirm every caller resolves to the survivor (grep -r "function_name(" app/ vendor/) and add a test that exercises it.

Handle missing extensions. If a package's autoload.files entry hard-requires an extension (or PHP version) your production image lacks, exclude that file and keep using the package's classes. This is often cleaner than forking the package or dropping it entirely.

Keep it out of the Laravel layer. There is no service provider, no config publish, no Artisan command — this is purely a Composer-time concern. Don't try to wrap it; instead, make the deploy pipeline assert it worked (see below). After changing it, php artisan optimize:clear and, on Octane, php artisan octane:reload.

Assert exclusions in CI/deploy. A tiny post-install check stops regressions cold:

composer install --no-dev --optimize-autoloader
php -r '$f = require "vendor/composer/autoload_files.php";
  foreach (["vendor/symfony/polyfill-php80/bootstrap.php"] as $p)
    if (in_array(realpath($p), array_map("realpath", $f), true)) { fwrite(STDERR, "exclusion missing: $p\n"); exit(1); }'

Docker pattern. Multi-stage builds often run composer install --no-plugins --no-scripts for speed/security. That flag combo defeats this plugin entirely — either allow plugins in the build stage or run the assert step above as a build gate.

Pair with --optimize-autoloader. Classmap optimization does nothing for files entries — they remain eager. This plugin is one of the few levers you have over that specific cost, which is exactly why it earns a slot in your deploy config.

Gotchas and Tips

  • allow-plugins is the #1 silent failure. On Composer 2.2+ an unallowed plugin is skipped without an obvious error in non-interactive mode. Run composer diagnose and look for the plugin line if exclusions "don't apply."
  • --no-plugins (and --no-scripts) silently disables everything. Common in Dockerfiles and CI caches. If you see the files still in autoload_files.php in prod but not locally, this is almost always why.
  • Editing extra without dumping does nothing. composer install normally re-dumps, but --no-autoloader and some cache-restore paths don't. When in doubt: composer dump-autoload -vvv.
  • Don't touch Laravel's own files. laravel/framework's src/Illuminate/Foundation/helpers.php and src/Illuminate/Support/helpers.php are eagerly loaded and every Blade/controller call depends on them. Excluding them yields Call to undefined function deep in the framework with a confusing stack trace.
  • Order matters. Files are loaded in dependency order. Removing a bootstrap that defines a constant, registers a stream wrapper, or sets a global can change behavior for files loaded after it — even if nothing references it by name. Smoke-test more than you think you need to.
  • autoload_static.php is regenerated too. Never hand-edit either file in vendor/; it's overwritten on every dump and won't exist in a clean CI checkout.
  • Path case and trailing slashes. Matching is path-string based. On Linux (CI/prod) a mismatched case or an extra / silently matches nothing — dev on macOS may hide this.
  • Opcache and long-lived workers. After changing exclusions, restart PHP-FPM and reload Octane workers; they hold the old autoloader in memory.
  • Custom vendor-dir. If you've relocated vendor, write paths relative to the project root as documented, not relative to vendor/.
  • Exclusions apply to tests too. PHPUnit loads vendor/autoload.php, so a bad exclusion usually blows up locally before it reaches prod — don't disable the suite to "make it pass."
  • Maturity risk is real but bounded. ~40 stars, single maintainer, no dependents. The plugin's surface area is tiny (rewrite a generated PHP array on autoload events), so the blast radius if it breaks is small and detectable. Pin it, review it on every Composer major/PHP upgrade, and keep the escape hatch in mind: a 30-line custom Composer plugin on post-autoload-dump, or a script that rewrites autoload_files.php, reproduces this behavior if the package ever stalls.
  • Debugging tip: composer dump-autoload -vvv shows plugin activity and event order. If an exclusion doesn't stick, check whether another plugin is rewriting the autoloader afterward — plugin ordering is registration-order dependent.
  • Confirm the file is actually in a dependency's autoload.files. Root-level files you declare yourself in composer.json are handled on a slightly different path: if you put a file there and list it in exclude-files, the intent is ambiguous and the result may surprise you. Remove it from autoload.files instead.
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle