Available — part-time slots from Q4 2026 UK · Remote BST · GMT+1
All fixes
F/07 9 min read reviewed Sep 2026· Strapi 5

Your config works locally and is ignored in production

TL;DR

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.

src/index.ts ts
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

bars = diagnostic order from experience, not measured frequency

Cause 01 of 02

Config lives in config/plugins or config/middlewares, but production reads config/env/production

Symptom

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.

How to confirm

Log the resolved config at boot, as above. If production shows defaults where your repo shows your settings, the environment-specific file is missing.

Why it happens

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.

The fix

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.

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

bars = diagnostic order from experience, not measured frequency

Cause 01 of 02

NODE_ENV isn't what you assume, so the env folder never loads

Symptom

The production file exists and is correct, and it is still ignored.

How to confirm

Log process.env.NODE_ENV at boot. If it is not production, config/env/production/ is never read.

The fix

Set NODE_ENV=production in the deployed environment. On some platforms it is unset, or set to something else, by default.

Common questions

Diagnosed everything and still stuck?

S/01 — Performance & Architecture Rescue.

A fixed-scope week that finds the cause and fixes what's causing it.