CORS for Local Development (localhost)
Handle CORS during local development when frontend and backend run on different ports. Covers proxy configuration, environment-based origins, and common localhost pitfalls.
Detailed Explanation
CORS and localhost
During development, your frontend typically runs on http://localhost:3000 while the API runs on http://localhost:8080. Because the port is part of the origin, these are different origins and CORS applies.
Option 1: Add localhost to Allowed Origins (Development Only)
const allowedOrigins = process.env.NODE_ENV === "production"
? ["https://app.example.com"]
: ["http://localhost:3000", "http://localhost:5173", "http://127.0.0.1:3000"];
app.use(cors({ origin: allowedOrigins, credentials: true }));
Option 2: Framework Dev Proxy (No CORS Needed)
Most frontend frameworks offer a development proxy that forwards API requests through the dev server, making them same-origin.
Vite:
// vite.config.ts
export default defineConfig({
server: {
proxy: {
"/api": "http://localhost:8080",
},
},
});
Next.js:
// next.config.js
module.exports = {
async rewrites() {
return [
{ source: "/api/:path*", destination: "http://localhost:8080/api/:path*" },
];
},
};
Create React App:
{ "proxy": "http://localhost:8080" }
Option 3: Wildcard in Development
app.use(cors({
origin: process.env.NODE_ENV === "production" ? "https://app.example.com" : "*",
}));
localhost vs 127.0.0.1
http://localhost:3000 and http://127.0.0.1:3000 are different origins. If your browser navigates to localhost but the API allowlist only includes 127.0.0.1, CORS will fail. Include both or use a proxy.
Common Pitfall: IPv6
On some systems, localhost resolves to ::1 (IPv6) instead of 127.0.0.1. Your backend may be listening on 127.0.0.1 only. Check with curl -v http://localhost:8080 to see which IP is used.
Use Case
A developer runs a React app on localhost:3000 and a Python Flask API on localhost:5000. They encounter CORS errors and want the simplest fix that doesn't involve changing server code — a frontend proxy.