Launch offer: everything is 100% off. Download any skill free, no sign-up. Get the skills
TechFixError fixesBroke after deploy
Broke after deploy

CORS error only in production, but it works on localhost

What the browser console shows
Access to fetch at 'https://api.example.com/items' from origin 'https://www.example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.

# Firefox:
Reason: CORS header 'Access-Control-Allow-Origin' missing
Short answer

Your API's list of allowed websites still only has http://localhost:3000. Add your real domain (exactly, scheme included) and redeploy the API.

Why it happens

When your page calls an API on a different domain, the browser asks the API whether that page's origin is allowed. If the response doesn't include an Access-Control-Allow-Origin header that matches, the browser blocks it.

It works locally because your allowlist says localhost. In production the origin is https://www.example.com, which isn't on the list. Other common causes: www versus no www, http versus https, a trailing slash in the configured origin, cookies sent with a wildcard origin, or the API crashing (error responses often have no CORS headers, so a 500 shows up as a CORS error).

Fix it by hand

  1. Look at the failing request. In the browser's Network tab, select the request. Note the Origin request header and the response status. If the status is 404 or 500, fix that first: the CORS message may be a side effect.
  2. Allow your exact production origin. Origins are scheme plus host plus port, with no path or trailing slash. With the Express cors package, read them from an environment variable so each environment can differ:
    const allowed = (process.env.CORS_ORIGINS || '').split(',');
    // CORS_ORIGINS=https://example.com,https://www.example.com
    app.use(cors({ origin: allowed, credentials: true }));
  3. If you send cookies or auth headers, don't use *. Browsers refuse a wildcard with credentials, and MDN warns against * for private APIs. Return the specific origin and add Vary: Origin if you set headers by hand.
  4. Handle preflight requests. Requests with custom headers or methods like PUT and DELETE send an OPTIONS request first. app.use(cors(...)) handles these for all routes. In Next.js, set the headers in the route handler or in proxy.ts and answer OPTIONS.
  5. Redeploy the API (not just the frontend), then hard-refresh the site and retry.

Stop it happening again

Let TechFix do this for you

Broke After Deploy $9

Broke After Deploy flags CORS configs that only allow localhost, frontend calls that still point at localhost, and http:// calls from an https site, before you deploy.

  • Checks your project for 37 known causes of "works locally, breaks in production" and runs your production build.
  • Paste the error and it finds the cause in your code, then lists what will break next.
  • Verdict first. Every finding shows the file and line, what it breaks, and the fix as a diff that is applied only with your OK.

Broke After Deploy: how it works, with examples · Install guide

Works with Claude Code, Claude.ai, Cursor, Codex and other agents that read SKILL.md files. No installs, no accounts, works offline. No-questions refund.

Sources (checked 2026-10-13)