Your config works locally and is ignored in production
The same commit behaves differently once it is deployed. Email goes out as no-reply@strapiapp.com despite a configured Mailgun provider, a custom auth header disappears and every request 401s, or images are blocked by a CSP you never wrote. In almost every case the cause is the same: your provider or middleware config lives in config/plugins or config/middlewares, and production is reading config/env/production instead. Confirm that before you change a single value: log the config Strapi actually resolved at boot, not the file you wrote.
00· Before anything
First: log the config Strapi actually resolved
The trap with environment config is that the file you are looking at is not the file production is reading. Before changing anything, prove which one won. Log the resolved value at boot from a bootstrap hook, and compare it against what is in your repository.
If the value you see in production is not the value in your repo, you are on the right page. If it matches, your problem is somewhere else and nothing below will help.
export default {
bootstrap({ strapi }) {
strapi.log.info(`NODE_ENV: ${process.env.NODE_ENV}`);
// The resolved config, after env-folder merging — not the file you edited.
strapi.log.info(
`middlewares: ${JSON.stringify(strapi.config.get('middlewares'))}`,
);
},
};This is the root cause sitting underneath several other production-only failures: a broken email provider, a missing upload provider, an unexpected CSP, a disappearing auth header. If the confirm step shows the wrong config in production, fix it once here and the downstream symptom usually goes with it.
Likely causes · The order I check them
Cause 01 of 02
Config lives in config/plugins or config/middlewares, but production reads config/env/production
Everything works in local development. Deployed, the provider or middleware behaves as if it was never configured: the default email sender, the local upload provider, the default middleware stack.
Log the resolved config at boot, as above. If production shows defaults where your repo shows your settings, the environment-specific file is missing.
Anything under config/env/{env}/ overrides the matching key in the default config for that environment. If production needs a value, it has to exist at config/env/production/, and the filename has to match the default exactly.
Move the production values into config/env/production/, mirroring the filename. config/plugins.ts becomes config/env/production/plugins.ts; config/middlewares.ts becomes config/env/production/middlewares.ts.
This merge is documented on the environment configuration page: everything defined in the production configuration overrides the default configuration for that environment.
Cause 02 of 02
On Strapi Cloud, the production middlewares file replaces the global array
You added one middleware for production and the rest of the stack stopped working: security, CORS, body parsing, the lot.
On Cloud, the production middlewares file does not merge into the global array, it replaces it. A partial file silently drops every middleware you did not re-list.
Include the complete middleware array in the production file, not just your addition. Start from the default stack and insert yours in the right position.
This is documented on the Cloud middlewares page: any changes to the global config/middlewares file are overwritten and will not take effect, and the production file replaces the array in full.
03
The full-replacement behaviour is documented for middlewares, not for plugins. For plugins the guidance is only to use the env path and match the filename exactly. Do not assume Cloud overwrites plugins.ts the same way. It does not.
Likely causes · The order I check them
Cause 01 of 02
NODE_ENV isn't what you assume, so the env folder never loads
The production file exists and is correct, and it is still ignored.
Log process.env.NODE_ENV at boot. If it is not production, config/env/production/ is never read.
Set NODE_ENV=production in the deployed environment. On some platforms it is unset, or set to something else, by default.
Cause 02 of 02
A platform-side regression
Config that is in the right place, with the right NODE_ENV, is still ignored, and it started after a platform update rather than a change of yours.
Pin down whether the behaviour changed without a corresponding change in your repository. Check your platform's changelog and status around the time it started.
Rare, but real: there was a period in 2026 where config/middlewares was ignored outright and the default Cloud stack served instead. If you have eliminated the causes above, look for a known platform issue and the version it was fixed in before spending more time in your own code.
Common questions
Only the keys that differ in production. The env file is merged over the default for that environment, so anything you do not override falls through to the base config. The one exception is the Cloud middlewares array, which is replaced in full rather than merged.
That is the default sender on Strapi Cloud when no email provider is resolved in production. It almost always means your provider config is in config/plugins but not in config/env/production/plugins.
Yes. The env-folder merge applies to every config file. The same rule that catches plugins and middlewares catches the server URL, proxy settings and database connection details.
Diagnosed everything and still stuck?
S/01 — Performance & Architecture Rescue.
A fixed-scope week that finds the cause and fixes what's causing it.