ARTICLE

Magento 2 Deploy Modes Explained: Developer vs Default vs Production, setup:di:compile, and the generated Directory

Magento 2 Deploy Modes Explained: Developer vs Default vs Production, setup:di:compile, and the generated Directory

Magento 2 has three application modes: developer, default, and production. Developer mode generates code and static files on demand and shows errors in the browser. Production mode serves only precompiled code from generated/ and prebuilt files from pub/static, and hides errors. Default mode sits in between and should never run a live store.

Most teams know that much. What causes trouble is the mechanics underneath: what gets generated, when it gets cleared, and why a module that works perfectly on a laptop throws “class does not exist” the moment it reaches production. This guide covers each mode in detail, what setup:di:compile builds, how to switch modes without leaving stale files behind, and a deploy order that keeps production stable.

The three modes at a glance

Adobe’s application modes reference describes how each mode behaves. The differences that matter day to day:

Behavior Developer Default Production
Static view files Written to pub/static on demand, not cached Generated on demand and cached Served only from prebuilt files in pub/static
Generated code (factories, proxies, interceptors) Generated automatically when first needed Generated when first needed Must be precompiled with setup:di:compile
Uncaught exceptions Shown in the browser Logged, not shown Logged, never shown
X-Magento-* debug headers Shown Hidden Hidden
Admin Developer settings Available Available Hidden; cache types managed from CLI only
Intended use Building and debugging Out-of-the-box fallback Live stores
Supported on Adobe Commerce Cloud No (except Cloud Docker locally) No Yes

A fourth state, maintenance mode, is not an application mode in the same sense. It is a flag file, var/.maintenance.flag, that shows visitors a “Service Temporarily Unavailable” page while letting allowlisted IP addresses through. Deploys toggle it on and off around the risky steps.

Developer mode: convenient, and that is the problem

Developer mode is designed for building. Adobe lists its behavior: static files are written to pub/static on demand, code compiles automatically, exceptions appear in the browser, var/report logging is verbose, and an exception is thrown when an event subscriber cannot be invoked.

That last behavior is useful. A broken observer fails loudly instead of being swallowed. The on-demand behavior, though, hides a whole class of bugs. When a class asks for ProductRepositoryInterfaceFactory or a \Proxy, developer mode generates that class the first time it is requested. Production mode will not. If the compiler never produced that class, production fails where developer mode quietly papered over the gap.

Developer mode is also slower. Static assets are resolved through the fallback chain on request, and generated classes are checked and created as needed. Never benchmark performance in developer mode and never leave a public store in it. Error output in the browser exposes file paths and stack traces.

Default mode: the mode nobody chooses on purpose

Magento runs in default mode when no mode is set in app/etc/env.php. Adobe describes it as “not optimized for production.” Static files are generated and cached on the fly, errors go to logs, and debug headers are hidden.

Default mode is mostly an accident. A fresh install lands there, and a store that was never explicitly switched stays there. Adobe notes that only developer and production modes are written to env.php, so an env.php with no MAGE_MODE entry usually means default. Run bin/magento deploy:mode:show on every environment you own. If any live store reports default, schedule the switch to production.

Production mode: everything is built ahead of time

Production mode assumes nothing gets generated at request time. Static files must already exist in pub/static, built by setup:static-content:deploy. Generated PHP must already exist in generated/, built by setup:di:compile. Errors are logged to the file system and never shown. Some Admin areas, including the Developer configuration section, disappear, and cache types can only be toggled from the command line.

The payoff is speed and safety. The trade-off is that every deploy has to build correctly, and a missing build step shows up as a broken storefront rather than a slow one.

What setup:di:compile actually generates

Adobe’s code compiler documentation lists what compilation covers:

  • Application code generation: factories and proxies.
  • Area configuration aggregation: optimized dependency injection configuration per area (frontend, adminhtml, webapi, and so on).
  • Interceptor generation: the Interceptor classes that make plugins work.
  • Interception cache generation: precomputed plugin lists.
  • Repositories code generation: generated code for APIs.
  • Service data attributes generation: the generated extension classes for data objects, such as ProductExtension.

The classes land in generated/code, and the compiled DI configuration lands in generated/metadata. A successful run ends with “Generated code and dependency injection configuration successfully.”

That list explains most production-only failures. A plugin that does nothing in production usually means stale interceptors. A “Call to undefined method” on an extension object usually means the extension classes were not regenerated after extension_attributes.xml changed. A missing factory or proxy usually means compilation was skipped, failed partway, or was run against a different codebase than the one being served.

Compilation also catches problems developer mode never surfaces, because it scans every class and DI definition at once. Running setup:di:compile in CI on every merge request is one of the cheapest checks a Magento team can add. If it fails in CI, it would have failed on the production deploy.

Switching modes safely

The commands are simple. Adobe’s mode switching guide covers the details:

bin/magento deploy:mode:show
bin/magento deploy:mode:set production
bin/magento deploy:mode:set developer

Run them as the file system owner, never as root. Files created by root become unwritable to PHP-FPM and cause permission errors on the next request.

Going to production

deploy:mode:set production does a lot in one command. It enables maintenance mode, deploys static view files for each theme and locale, minifies templates, processes LESS and deploys CSS, runs code compilation, and disables maintenance mode. The --skip-compilation flag skips the compile step. That is useful when your pipeline compiles separately, but it means you must run setup:di:compile yourself before the store takes traffic.

Switching to developer or production clears var/cache, generated/metadata, generated/code, var/view_preprocessed, and pub/static. It keeps .htaccess files and the static content version file.

Going back to developer

Adobe’s guidance is to clear generated code before switching from production to developer:

rm -rf generated/metadata/* generated/code/*
bin/magento deploy:mode:set developer

Skipping this leaves precompiled DI metadata in place, so Magento keeps using the old configuration and your new plugins or preferences appear to be ignored. This is one of the most common reasons a developer says “my di.xml change does nothing.”

Environment variables can override the mode

deploy:mode:show warns that environment variables may override the stored value. If MAGE_MODE is set in the web server or PHP-FPM pool configuration, it wins over env.php. When the CLI says production but the storefront behaves like developer mode, check the server configuration for MAGE_MODE.

A production deploy order that works

The order of build steps matters because each one depends on the last. For a self-hosted store, a sequence that holds up:

Step Command Where it runs Why this order
1 composer install --no-dev Build Code and vendor must be final before anything is generated
2 bin/magento setup:di:compile Build Generated classes reflect the exact code being shipped
3 bin/magento setup:static-content:deploy Build Static files reflect the exact themes and modules shipped
4 bin/magento maintenance:enable Production Protect customers during schema changes
5 bin/magento setup:upgrade --keep-generated Production Runs schema and data patches without wiping the build
6 bin/magento cache:flush Production Drop configuration and layout caches from the old release
7 bin/magento maintenance:disable Production Back to serving traffic

Step 5 is where many pipelines go wrong. By default, setup:upgrade clears generated code, which in production mode means the store has no compiled classes until you compile again. The --keep-generated option keeps the build you just made. Adobe describes it as an option for experienced integrators, used only in production mode, that does not update static view files. That fits this pipeline exactly, because static files and generated code were already built in steps 2 and 3.

Steps 1 through 3 belong on a build machine or CI runner, not on the production web servers. Building on the live server means the store runs a half-compiled codebase while compilation is in progress. Pair this with an atomic release directory swap and the live store only ever sees a complete build. We cover that side in zero-downtime Magento deploys with Deployer, and the static content step in depth in Magento 2 static content deploy strategies.

Composer is the foundation under all of this. If composer.lock is not committed and respected, two builds of the same commit can compile different code. Our guide to Magento 2 Composer and dependency management covers lock files and patching.

Adobe Commerce Cloud: production only

On Adobe Commerce Cloud, you do not pick a mode. Adobe states that changing modes in remote Cloud environments is restricted by the read-only file system, and Support cannot override it. Developer mode is not supported in Cloud environments. Do not edit app/etc/env.php to change modes there, because ece-tools overwrites it on deploy.

Cloud deploys switch the site into maintenance mode automatically and back to production when they finish. For local work, Cloud Docker can run in developer mode, though Adobe notes it is slower because of extra file synchronization. In practice, Cloud teams do their developer-mode work locally and treat every remote environment, including integration branches, as production.

Hyva storefronts and modes

Hyva does not change how modes work, but it changes what you notice. In developer mode, Hyva’s Tailwind styles come from whatever you last built with the Tailwind CLI or watcher, not from Magento’s on-demand static file generation. If styles look right locally and wrong in production, the cause is almost always the Tailwind production build rather than the mode. The deploy order still applies. Build Tailwind CSS before step 3 so the static content deploy picks up the compiled stylesheet.

Hyva’s Alpine.js components live in templates, so there is no RequireJS bundling or minification to configure per mode. That removes one common source of “works in developer, breaks in production” bugs that Luma stores still have.

Troubleshooting: works in developer, broken in production

Symptom in production Likely cause Fix
Class ...Factory does not exist or ...Proxy does not exist Compilation skipped, failed, or ran on different code Rerun setup:di:compile on the exact release; add it to CI
New plugin or preference has no effect Stale generated/metadata Clear generated/code and generated/metadata, recompile
Storefront unstyled or 404s on CSS and JS Static content not deployed for that theme or locale Run setup:static-content:deploy for the live themes and locales
Site down right after setup:upgrade Generated code wiped by setup:upgrade Use --keep-generated, or recompile before leaving maintenance
White page with no error Errors hidden in production Check var/log/exception.log and var/report
Permission denied writing generated/ or var/ CLI ran as root Run commands as the file system owner; fix ownership
CLI says production, site behaves like developer MAGE_MODE set in server config Remove or align the environment variable

Getting this right on your stack

Modes are one of the first things we check when a Magento store feels fragile on deploy day. A store in default mode, a pipeline that runs setup:upgrade without --keep-generated, or builds that run on the live servers can each explain a lot of release-night incidents.

If you want a second set of eyes on your deployment pipeline, our Magento development services team works on Adobe Commerce builds, upgrades, and release processes, and our Hyva development services cover the Tailwind build and theme side of the same pipeline. Bemeir is a Brooklyn ecommerce agency built around Magento, Adobe Commerce, and Hyva. Read more about Bemeir and the technology partners we work with. When a different platform fits better, we also build on Shopify, Shopware, and BigCommerce.

FAQ

What is the difference between Magento developer mode and production mode?

Developer mode generates classes and static files on demand and shows errors in the browser, which is convenient for building but slow and unsafe for live traffic. Production mode serves only precompiled code from generated/ and prebuilt files from pub/static, logs errors instead of showing them, and hides the Admin Developer settings.

Do I need to run setup:di:compile in developer mode?

No. Developer mode generates factories, proxies, and interceptors automatically when they are first needed. Running setup:di:compile locally is still worthwhile before you push, because it scans every class at once and catches DI errors that developer mode only reveals in production.

Why does my Magento store break after running setup:upgrade in production?

By default setup:upgrade clears generated code, so a production store has no compiled classes until compilation runs again. Either recompile before disabling maintenance mode, or run setup:upgrade --keep-generated when you have already compiled the same release on a build machine.

How do I check which mode my Magento store is in?

Run bin/magento deploy:mode:show as the file system owner. If the store reports default mode, it was never switched and should be moved to production. Also check the web server and PHP-FPM configuration for a MAGE_MODE environment variable, which overrides the value in app/etc/env.php.

Can I use developer mode on Adobe Commerce Cloud?

No. Adobe Commerce Cloud supports only production and maintenance modes in remote environments, and the read-only file system blocks mode changes. Use Cloud Docker locally if you need developer mode, and treat every remote Cloud environment as production.

Let us help you get started on a project with Magento 2 Deploy Modes Explained: Developer vs Default vs Production, setup:di:compile, and the generated Directory and leverage our partnership to your fullest advantage. Fill out the contact form below to get started.

more articles about ecommerce

Read on the latest with Shopify, Magento, eCommerce topics and more.