Problem Statement
The setup/ directory is a standalone Laminas (Zend) MVC application that was originally built for the web-based Setup Wizard. The web installer has been officially deprecated (classes annotated with @deprecated, blocked by default in nginx.conf.sample), yet the entire setup/ directory remains a hard runtime dependency for every bin/magento invocation.
Current state
-
Magento\Framework\Console\Cli unconditionally requires setup/config/application.config.php and bootstraps a Laminas ServiceManager on every CLI call — even for cache:flush or indexer:reindex.
-
app/etc/di.xml maps core Framework interfaces to Magento\Setup\* implementations:
<preference for="Magento\Framework\Setup\SchemaSetupInterface" type="Magento\Setup\Module\Setup" />
<preference for="Magento\Framework\Setup\ModuleDataSetupInterface" type="Magento\Setup\Module\DataSetup" />
-
app/code/Magento/Backend extends Magento\Setup\Console\Command\AbstractSetupCommand for maintenance commands.
-
The composer.json PSR-4 autoload and registration_globlist.php both reference setup/.
This means removing setup/ from a production artifact breaks bin/magento entirely — even though a deployed production store never needs the installer, DI compiler, or static content deployer at runtime.
What's dead but still shipped
| Component |
Files |
Status |
Web installer entry point (setup/index.php) |
1 |
Deprecated, blocked in nginx |
Laminas views & templates (setup/view/) |
~10 |
Deprecated, unused |
Static assets (setup/pub/) |
~15 |
Deprecated, unused |
Web controllers (setup/src/.../Controller/) |
~5 |
Deprecated |
| Laminas MVC bootstrap listeners |
~3 |
Annotated @deprecated |
| Performance toolkit fixtures |
~20 |
Dev-only |
DI Compiler (Module/Di/) |
~50 |
Build-time only |
I18n tools (Module/I18n/) |
~30 |
Build-time only |
Dependency analysis (Module/Dependency/) |
~40 |
Dev-time only |
~170+ files that serve no purpose in production are required to be deployed.
Security concern
Shipping setup/ in production artifacts encourages (or requires) exposing the directory on web servers. Even with deny all in nginx, misconfigured servers can leak:
- Magento version information via
setup/view/ templates
- Internal directory structure
- The setup entry point itself (historically a common attack vector)
The safest file is the one that doesn't exist on the server.
Expected State
Short-term (non-breaking)
-
Make Cli.php setup-tolerant — Load setup/config/application.config.php conditionally with a class_exists() / file_exists() guard. If setup/ is absent, skip SetupCommandLoader registration. Non-setup commands (cache:*, indexer:*, cron:*) should work without setup/.
-
Move runtime DI implementations to Framework — Magento\Setup\Module\Setup and Magento\Setup\Module\DataSetup contain minimal logic on top of Magento\Framework\Module\Setup. Move them into lib/internal/Magento/Framework/Setup/ and update di.xml preferences. These are the only two classes needed at runtime.
-
Move AbstractSetupCommand to Framework — Backend's maintenance commands should not depend on the Magento\Setup namespace.
After these 3 changes, setup/ can be safely excluded from production deploys while keeping bin/magento fully functional for operational commands.
Long-term (next major version)
-
Relocate CLI commands to proper Magento modules — Register setup:* commands via di.xml like every other command, eliminating the Laminas ServiceManager bootstrap entirely.
-
Remove the dead web installer code — Delete deprecated controllers, views, pub assets, Laminas MVC listeners.
-
Extract build-time tools into separate packages — DI compiler, I18n tools, dependency analysis as magento/setup-tools or similar.
Impact
- Performance: Every
bin/magento call bootstraps Laminas ServiceManager unnecessarily
- Security: Reduced attack surface by not shipping installer code to production
- DevOps: Smaller, cleaner production artifacts; no need to maintain nginx rules for a dead feature
- Architecture: Removes the last Laminas MVC dependency from the runtime path
⭐ Support my work
Do you like the fix? Remember to react with "👍🏻" to get it merged faster,
Then Sponsor me on Github so I can spend more time on fixing issues like this one.
Learn more at https://github.com/sponsors/lbajsarowicz
Problem Statement
The
setup/directory is a standalone Laminas (Zend) MVC application that was originally built for the web-based Setup Wizard. The web installer has been officially deprecated (classes annotated with@deprecated, blocked by default innginx.conf.sample), yet the entiresetup/directory remains a hard runtime dependency for everybin/magentoinvocation.Current state
Magento\Framework\Console\Cliunconditionally requiressetup/config/application.config.phpand bootstraps a LaminasServiceManageron every CLI call — even forcache:flushorindexer:reindex.app/etc/di.xmlmaps core Framework interfaces toMagento\Setup\*implementations:app/code/Magento/BackendextendsMagento\Setup\Console\Command\AbstractSetupCommandfor maintenance commands.The
composer.jsonPSR-4 autoload andregistration_globlist.phpboth referencesetup/.This means removing
setup/from a production artifact breaksbin/magentoentirely — even though a deployed production store never needs the installer, DI compiler, or static content deployer at runtime.What's dead but still shipped
setup/index.php)setup/view/)setup/pub/)setup/src/.../Controller/)@deprecatedModule/Di/)Module/I18n/)Module/Dependency/)~170+ files that serve no purpose in production are required to be deployed.
Security concern
Shipping
setup/in production artifacts encourages (or requires) exposing the directory on web servers. Even withdeny allin nginx, misconfigured servers can leak:setup/view/templatesThe safest file is the one that doesn't exist on the server.
Expected State
Short-term (non-breaking)
Make
Cli.phpsetup-tolerant — Loadsetup/config/application.config.phpconditionally with aclass_exists()/file_exists()guard. Ifsetup/is absent, skipSetupCommandLoaderregistration. Non-setup commands (cache:*,indexer:*,cron:*) should work withoutsetup/.Move runtime DI implementations to Framework —
Magento\Setup\Module\SetupandMagento\Setup\Module\DataSetupcontain minimal logic on top ofMagento\Framework\Module\Setup. Move them intolib/internal/Magento/Framework/Setup/and updatedi.xmlpreferences. These are the only two classes needed at runtime.Move
AbstractSetupCommandto Framework — Backend's maintenance commands should not depend on theMagento\Setupnamespace.After these 3 changes,
setup/can be safely excluded from production deploys while keepingbin/magentofully functional for operational commands.Long-term (next major version)
Relocate CLI commands to proper Magento modules — Register
setup:*commands viadi.xmllike every other command, eliminating the LaminasServiceManagerbootstrap entirely.Remove the dead web installer code — Delete deprecated controllers, views, pub assets, Laminas MVC listeners.
Extract build-time tools into separate packages — DI compiler, I18n tools, dependency analysis as
magento/setup-toolsor similar.Impact
bin/magentocall bootstraps Laminas ServiceManager unnecessarily⭐ Support my work
Do you like the fix? Remember to react with "👍🏻" to get it merged faster,
Then Sponsor me on Github so I can spend more time on fixing issues like this one.
Learn more at https://github.com/sponsors/lbajsarowicz