How-to

5 ways to fix CORS in development

Your fetch() works in Postman but fails in the browser with "blocked by CORS policy". Five fixes you can land today, in order of how production-safe each one is.

~6 min read

1 — Configure CORS on the API (the real fix)

If you control the upstream, this is the only fix that's also correct in production. Add the right Access-Control-Allow-Origin header on the API and the browser stops blocking. See our full walk-through with code for Node, Go, and Python.

If the upstream is a third party you don't control, skip to options 2–5.

2 — Vite's dev-server proxy

Vite ships a built-in HTTP proxy that's perfect for development: requests to /api/* get forwarded to the upstream server-side, so the browser never sees a cross-origin request.

// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

Your code calls fetch('/api/users') instead of fetch('https://api.example.com/users'). Same-origin in dev, no CORS error.

Catch: only works in development. Your production build still hits the upstream directly, so you'll hit the same CORS error when deployed unless option 1 is also done.

3 — webpack-dev-server proxy

Same idea for Create React App, Vue CLI, and any other webpack-based dev server. CRA has a one-liner:

// package.json
{
  "name": "my-app",
  "proxy": "https://api.example.com"
}

Or for finer control:

// craco.config.js / webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        pathRewrite: { '^/api': '' },
      },
    },
  },
};

Same dev-only caveat as Vite.

4 — Launch a browser with web security disabled

The nuclear "I just need this one screenshot to work" option:

# Chrome / Chromium on macOS
open -na "Google Chrome" --args \
  --user-data-dir=/tmp/chrome-no-cors \
  --disable-web-security

Note the --user-data-dir with a fresh path — Chrome won't let you disable CORS in a session that has other profiles loaded, for obvious reasons.

When to use: very rarely. It's fine for "I'm screencasting a demo and the third-party CORS broke five minutes before recording" but you should never test your real product with it. Code that works only with web security off is code that's broken; turning the safeties back on will surface bugs nobody saw.

5 — Use a CORS proxy

For everything in between — third-party APIs, partner integrations, hackathon prototypes, "we'll fix it properly later" production hot paths — route through a CORS proxy. The browser sees the response coming from the proxy's origin (which sends the right headers), so CORS doesn't block.

// Before
fetch('https://api.example.com/data')

// After — managed proxy
fetch('https://api.corsproxy.dev/proxy?url=' +
      encodeURIComponent('https://api.example.com/data'), {
  headers: { 'X-API-Key': 'sk_live_...' }
});

You can also self-host the same proxy — same request format, no auth required, but you maintain the hosting. See our self-host vs managed guide for the tradeoff.

Quick reference

Fix Works in prod? Effort
Server-side CORSYesLow (if you own the API)
Vite proxyNoTiny
webpack proxyNoTiny
Disabled-security browserNeverZero
CORS proxyYes (with caveats)Tiny

Get a free key

100 requests/day, no credit card. Enough for development and most prototypes.

Sign in to get started →