What is Magento env.php ?
app/etc/env.php is Magento 2’s environment-specific configuration file — generated by bin/magento setup:install and gitignored by default. It holds the DB credentials, the crypt.key that encrypts payment tokens, the admin frontname, MAGE_MODE, and the Redis / RabbitMQ / cache backends. Paired with the git-tracked app/etc/config.php (enabled modules, themes, payment methods) it forms the full Magento config — shared config in git, secrets in env.php.
Five steps from setup:install to a hardened, multi-host env.php
env.php is the smallest file in a Magento install and the single biggest blast radius. Here is how it’s generated, where it’s read, and how to change it safely on a running site.
-
01
bin/magento setup:installgenerates env.phpDuring first install, the Magento CLI prompts for DB host, DB name, DB user, DB password, admin frontname, and base URL — then writes them plus a freshly-randomized
crypt.keyintoapp/etc/env.phpas a plain PHPreturn [ ... ]array. The same array also getsinstall.date, a defaultsession.savebackend, file-cache backends per cache region, and thecache_typesenabled-flags map. There is no GUI for editing env.php — you either re-run setup:install (destructive) or hand-edit the file on the server (preferred for live). -
02
Magento boots and reads env.php BEFORE any DB connection
app/bootstrap.phprequiresapp/etc/env.phpas one of the very first steps of every Magento request — before the DI container, before any DB connection, before any module loads. Every subsequent connection (MySQL, Redis cache, Redis session, RabbitMQ queue, OpenSearch) reads its credentials from env.php. That means a typo in env.php fails fast with a fatal at boot, rather than a cryptic 500 deep in a module. The file is parsed exactly once per PHP-FPM worker process, then cached in opcache. -
03
config.php commits to git, env.php does not
Magento’s shipped
.gitignorelistsapp/etc/env.phpby default. The companion fileapp/etc/config.php— which holds the enabled-modules array, theme registrations, and payment-method enable flags — IS tracked in git. CI/CD pipelines inject env.php at deploy time from a secrets manager: AWS Secrets Manager, HashiCorp Vault, Cloudflare Secrets, or sealed Kubernetes secrets viakubeseal. On Adobe Commerce Cloud, env.php is templated from environment variables at container start. -
04
Multi-host clusters coordinate via env.php
For a multi-server Magento cluster (web tier + app tier + DB + Redis + RabbitMQ + OpenSearch), env.php on each web/app node points at the shared DB host, the shared Redis host, the shared queue host. config.php is identical across every node because it lives in git. env.php differs per environment (dev / staging / prod) and per tier — same
crypt.keyandMAGE_MODEwithin an environment, different DB / Redis hosts and different queue creds. The crypt-key must match across all nodes that touch the same DB or token-decryption breaks. -
05
Updating env.php on a running site
DB / cache / queue host changes can be made by overwriting env.php and running
bin/magento cache:flush— no setup:upgrade needed for credential rotation alone.crypt.keychanges usebin/magento encryption:key:change, which also re-encrypts every DB column that used the old key.MAGE_MODEchanges usebin/magento deploy:mode:set production(which sets the flag plus runs the production-mode side effects). PHP-FPM workers cache env.php in opcache, so always reload PHP-FPM after a host or credential change.
Four scenarios where env.php is the file you actually touch
env.php sits unread for 99% of a Magento developer’s day. These four moments are when you stop, open it, and edit carefully.
-
First install — audit the freshly-generated env.php
Within 15 minutes of running
setup:install, open env.php and verify three things. One: the DB user is NOTroot— it should be a dedicatedmagentouser with grants only on the Magento DB. Two:crypt.keyis a long random hex string, not a placeholder or recycled across environments. Three:backend.frontNameis NOT the defaultadmin— it should be a random 10 – 12 char slug so admin-login brute-force attempts never find the URL. Fixing this on day one is trivial; fixing it on day 300 is a security incident. -
After migrating hosting
env.php is the file you edit when moving Magento to new hosting. Update
db.connection.default.host+username+password+dbname, pointcache.frontend.*.backend_options.serverat the new Redis host, pointqueue.amqp.hostat the new RabbitMQ, then runbin/magento cache:flushand reload PHP-FPM. config.php travels via git so the enabled-modules list and theme registrations come along for free.crypt.keyMUST be copied from the source env.php or every payment token, integration secret, and saved-card stored in the DB becomes garbage. -
Hardening a production install
env.php is half of Magento’s production hardening checklist. Change
backend.frontNamefromadminto a random 12-char slug. Setsession.savetoredis(file sessions don’t scale and leak to disk). Configurecache.frontend.default.backendtoMagento\Framework\Cache\Backend\Rediswith a dedicated DB index. Setlock.providertodbso cron locks survive across web nodes. SetMAGE_MODEtoproduction. File permissions on env.php should be440owned by the deploy user, readable only by deploy + php-fpm groups. -
Disaster recovery
env.php + database dump + media folder are the three artefacts you need to fully restore a Magento store from cold. Lose env.php and you lose the
crypt.key, which means every saved payment token, every integration secret, every encrypted DB column becomes unrecoverable — you’d need to re-issue every API key, force every customer to re-add their card, and re-link every third-party integration. ALWAYS back up env.php alongside the DB dump (in encrypted, separately-stored vaults — never the same bucket), and ALWAYS test the restore on a fresh box once a quarter.
Three env.php mistakes that turn into incidents
Every env.php-related incident I’ve been called in to clean up started as one of these three. Audit your repo, your backup policy, and your deploy script before they bite.
-
Committing env.php to source control
The most common — and most damaging — mistake. Committing env.php leaks the DB password, the
crypt.key, the adminbackend.frontName, and the queue / cache credentials into git history. Even on a private repo this is a breach: every contractor, every former dev, every CI runner, and every GitHub OAuth app with repo access now has production credentials in their git cache. If it happens, treat it as a confirmed breach: rotate the DB password, runencryption:key:change, renamebackend.frontName, rotate every payment-gateway API key referenced in the DB, and rewrite git history to scrub the file (and assume someone already cloned). -
Backing up the database without backing up env.php
Your nightly
mysqldumpis only half a backup. Magento encrypts payment tokens, third-party integration credentials, OAuth secrets, and a handful of other sensitive DB columns using thecrypt.keyfrom env.php. Restore the DB dump onto a fresh box without the matching env.php and those columns become unreadable garbage — the store boots, but every saved card, every Stripe customer reference, every integration breaks. ALWAYS back up env.php alongside the DB dump, store them in separate encrypted vaults, and document thecrypt.keyrotation history so a restore from 6 months ago finds the right key. -
Editing env.php on production without reloading PHP-FPM
Magento’s bootstrap reads env.php once per PHP-FPM worker process and opcode-caches it. After editing env.php on production — particularly
cache.frontend.*,session.save, ordb.connection.*— existing PHP-FPM workers keep using the OLD config until they recycle, which can be minutes-to-hours depending onpm.max_requests. Symptoms: half your requests use the new Redis host, the other half use the old one; sessions get split-brained; users get logged out at random. Fix: always pair an env.php edit withsystemctl reload php-fpmANDbin/magento cache:flush, in that order.
Magento env.php — frequently asked questions
-
Can I store env.php in source control?
No — env.php contains the DB password, the crypt-key, queue credentials, and the admin frontname. Committing it is treated as a confirmed credentials breach by every Magento agency I know. The standard workaround is to track an <code>env.php.example</code> file in the repo with placeholder values (e.g. <code>DB_PASSWORD_PLACEHOLDER</code>) so other developers can see the expected shape, then inject the real env.php at deploy time from a secrets manager (AWS Secrets Manager, HashiCorp Vault, Cloudflare Secrets, or sealed Kubernetes secrets). On Adobe Commerce Cloud, Adobe handles this automatically via environment variables. On self-hosted, your CI/CD pipeline writes env.php just before <code>bin/magento setup:upgrade</code> runs. -
What is the difference between env.php and config.php?
env.php is environment-specific and contains secrets: DB host / user / password, crypt-key, admin frontname, Redis / queue creds, MAGE_MODE, install date. It is gitignored by default. config.php is shared across environments and contains non-sensitive structural config: the enabled-modules array, theme registrations, store / website / view scopes, payment-method enable flags (not credentials), and shipping-method enable flags. config.php IS tracked in git so the same modules and themes are enabled across dev / staging / prod. Together env.php + config.php = the full Magento configuration. The split is deliberate: config travels via git, secrets travel via secrets-manager. -
How do I rotate the DB password in env.php?
Edit <code>db.connection.default.password</code> in env.php on every web / app node, then reload PHP-FPM (<code>systemctl reload php-fpm</code>) and flush the Magento cache (<code>bin/magento cache:flush</code>). That’s the entire process — there is no Magento CLI command for DB credential rotation, it’s just a file edit. The order matters: update the DB user’s password in MySQL first, then update env.php on every node within seconds (so the old workers can’t reach MySQL with the stale password), then reload PHP-FPM to flush the opcache-cached env.php. For zero-downtime rotation across many nodes, grant the new password as a second auth method temporarily, rotate the file on each node, then drop the old password from MySQL. -
Where does Adobe Commerce Cloud store env.php?
Adobe Commerce Cloud (the managed PaaS) does not store env.php as a file in the project at all — instead, the platform injects env.php contents at container build / start time from encrypted environment variables. You configure DB / Redis / queue endpoints via the project YAML files (<code>.magento.app.yaml</code>, <code>.magento/services.yaml</code>) and via environment-scoped variables in the Adobe Cloud dashboard. The crypt-key is managed automatically by Adobe per environment. When a container boots, Adobe’s ECE-Tools <code>build:generate</code> step writes the templated env.php into the container. This is why Adobe Commerce Cloud env.php questions usually resolve to YAML config questions, not file edits. -
Can env.php live outside app/etc/?
No — Magento’s bootstrap path is hard-coded. <code>app/bootstrap.php</code> requires <code>app/etc/env.php</code> via a relative path resolved against <code>BP</code> (the Magento base path constant). There is no configuration knob to relocate it. If you need to keep env.php on a separate volume for security reasons, the standard pattern is to mount the secret volume at <code>/srv/secrets/env.php</code> on the host, then symlink <code>app/etc/env.php -> /srv/secrets/env.php</code> in the deploy step. Magento doesn’t care that it’s a symlink as long as the path resolves and the file is readable. Adobe Commerce Cloud does effectively the same thing via container layer mounts. -
How do I disable opcache for env.php specifically?
You don’t need to — env.php is a normal PHP file and opcache handles it correctly. If you’re seeing stale env.php after an edit on production, the issue is NOT opcache validation timestamps (those default to 2 seconds), it’s PHP-FPM workers holding the OLD env.php contents in memory from when they first booted. Magento’s bootstrap reads env.php once per worker process via <code>require</code>, and the parsed array is held in the worker’s memory for the life of that worker (typically 500 – 1000 requests). The fix is to reload PHP-FPM (<code>systemctl reload php-fpm</code>) after editing env.php, which gracefully recycles all workers. Disabling opcache slows the whole site down by 2 – 4x and won’t fix the stale-config problem.
Want a security audit of your Magento env.php?
Send me read-only SSH access — I will audit your env.php file permissions, crypt-key rotation history, secrets-manager wiring, backup coverage, and gitignore hygiene, then reply with a written hardening plan, fixed-price quote, and earliest start date. 24-business-hour turnaround.