CORS errors in Replit typically stem from three sources: missing CORS middleware on your Express server, Replit's Replshield 307 redirect stripping CORS headers in deployed apps, or frontend and backend running on different origins. Fix them by adding the cors middleware to Express, deploying frontend and backend on the same Repl, using HTTPS exclusively, and switching from .repl.co to .replit.dev domains. The Replshield issue is a known platform behavior affecting thousands of users since 2025.
Debug and Fix CORS Errors in Replit-Hosted API Projects
Cross-Origin Resource Sharing (CORS) errors are among the most frustrating issues when deploying API projects on Replit. Your app works perfectly in the development preview but breaks in production with errors about missing Access-Control-Allow-Origin headers. This tutorial explains why CORS errors occur in Replit, covers the specific Replshield redirect issue unique to the platform, and provides working solutions for Express-based APIs. It is for intermediate developers who understand basic HTTP concepts and need to fix CORS problems in their deployed Replit apps.
Prerequisites
- A Replit project with an Express (Node.js) backend serving an API
- Basic understanding of what CORS is and why browsers enforce it
- Familiarity with HTTP headers and request/response flow
- An app experiencing CORS errors in deployment (or wanting to prevent them)
Step-by-step guide
Identify the CORS error in your browser console
Identify the CORS error in your browser console
Open your deployed app in a browser and press F12 to open DevTools. Click the Console tab. CORS errors appear as red messages like: Access to XMLHttpRequest at 'https://your-api.replit.app/data' from origin 'https://your-frontend.replit.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. This error means the browser is blocking the response because the server did not include the required CORS headers. Note the two different origins in the error message: the frontend origin making the request and the backend origin receiving it.
Expected result: You can identify the specific CORS error message in DevTools Console, noting the frontend origin and backend origin.
Install and configure the Express CORS middleware
Install and configure the Express CORS middleware
The most common fix is adding the cors npm package to your Express server. Open the Shell and install it, then import and use it in your server code. The simplest configuration allows all origins, which works for development but should be restricted in production. For production, specify the exact origins that are allowed to call your API. The middleware automatically handles preflight OPTIONS requests that browsers send before cross-origin POST, PUT, and DELETE requests.
1const express = require('express');2const cors = require('cors');34const app = express();56// Option 1: Allow all origins (development only)7app.use(cors());89// Option 2: Allow specific origins (production recommended)10app.use(cors({11 origin: [12 'https://your-frontend.replit.app',13 'https://yourdomain.com'14 ],15 methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],16 allowedHeaders: ['Content-Type', 'Authorization'],17 credentials: true18}));1920app.get('/api/data', (req, res) => {21 res.json({ message: 'CORS is working' });22});2324app.listen(3000, '0.0.0.0');Expected result: Your Express server includes CORS headers in all responses, and cross-origin requests from allowed origins succeed.
Handle the Replshield 307 redirect issue
Handle the Replshield 307 redirect issue
Replit uses a service called Replshield that adds a 307 Temporary Redirect to https://replshield.replit.dev/ on first requests to deployed apps. This redirect strips your CORS headers, causing errors even when your Express CORS middleware is correctly configured. This is a known platform-level issue reported since July 2025 affecting thousands of users. The redirect typically occurs on the first request or after periods of inactivity, making it intermittent and difficult to debug. The most reliable workaround is to deploy your frontend and backend in the same Repl so all requests are same-origin, eliminating the need for CORS entirely.
Expected result: You understand the Replshield issue and can choose the appropriate workaround for your architecture.
Combine frontend and backend in the same Repl
Combine frontend and backend in the same Repl
The most reliable way to avoid CORS issues on Replit is to serve your frontend from the same Express server that provides your API. This makes all requests same-origin, so CORS restrictions never apply. Configure Express to serve static files from a public or dist directory and handle API routes separately. This approach works with both React builds and plain HTML/CSS/JS frontends. Build your React app into the dist folder and let Express serve it alongside your API routes.
1const express = require('express');2const path = require('path');34const app = express();56// Parse JSON request bodies7app.use(express.json());89// Serve API routes first10app.get('/api/data', (req, res) => {11 res.json({ message: 'Hello from the API', timestamp: Date.now() });12});1314app.post('/api/submit', (req, res) => {15 const { name } = req.body;16 res.json({ received: name });17});1819// Serve static frontend files20app.use(express.static(path.join(__dirname, 'public')));2122// Catch-all: serve index.html for client-side routing23app.get('*', (req, res) => {24 res.sendFile(path.join(__dirname, 'public', 'index.html'));25});2627app.listen(3000, '0.0.0.0', () => {28 console.log('Server running on port 3000');29});Expected result: Your frontend and API are served from the same origin, and CORS errors no longer occur.
Set up a same-origin proxy for development
Set up a same-origin proxy for development
If you use a React development server (like Vite or Create React App) alongside an Express backend during development, the two servers run on different ports, causing CORS issues. Instead of adding CORS middleware just for development, set up a proxy in your frontend configuration. Vite supports a proxy option in vite.config.ts that forwards API requests to your backend server. This keeps all requests same-origin from the browser's perspective during development.
1// vite.config.ts2import { defineConfig } from 'vite';3import react from '@vitejs/plugin-react';45export default defineConfig({6 plugins: [react()],7 server: {8 proxy: {9 '/api': {10 target: 'http://localhost:3001',11 changeOrigin: true,12 }13 }14 }15});Expected result: Frontend requests to /api/* are proxied to your backend server during development, avoiding CORS issues.
Test CORS configuration across environments
Test CORS configuration across environments
After implementing your fix, test in multiple scenarios: the Replit workspace preview, a direct browser visit to the deployed URL, and from an external domain if applicable. Use the Network tab in DevTools to inspect response headers and verify that Access-Control-Allow-Origin is present. Also test after the app has been idle for 15+ minutes (on Autoscale deployments) to catch the cold-start Replshield redirect issue. For persistent CORS issues in production deployments that resist standard fixes, RapidDev can diagnose platform-specific problems and recommend architectural solutions.
Expected result: API responses include correct CORS headers in all environments, and cross-origin requests succeed without errors.
Complete working example
1const express = require('express');2const cors = require('cors');3const path = require('path');45const app = express();6const PORT = 3000;78// Determine allowed origins based on environment9const isProduction = process.env.REPLIT_DEPLOYMENT === '1';10const allowedOrigins = isProduction11 ? [12 `https://${process.env.REPLIT_DOMAINS}`,13 'https://yourdomain.com',14 ]15 : ['*'];1617// CORS middleware — configured for Replit deployment18app.use(cors({19 origin: isProduction20 ? (origin, callback) => {21 if (!origin || allowedOrigins.includes(origin)) {22 callback(null, true);23 } else {24 callback(new Error('Not allowed by CORS'));25 }26 }27 : '*',28 methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],29 allowedHeaders: ['Content-Type', 'Authorization'],30 credentials: isProduction,31}));3233// Ensure HTTPS in production (avoids mixed content CORS issues)34if (isProduction) {35 app.use((req, res, next) => {36 if (req.headers['x-forwarded-proto'] !== 'https') {37 return res.redirect(`https://${req.headers.host}${req.url}`);38 }39 next();40 });41}4243app.use(express.json());4445// API routes46app.get('/api/health', (req, res) => {47 res.json({ status: 'ok', environment: isProduction ? 'production' : 'development' });48});4950app.get('/api/data', (req, res) => {51 res.json({ items: [{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }] });52});5354// Serve static frontend (same-origin solution)55app.use(express.static(path.join(__dirname, 'public')));56app.get('*', (req, res) => {57 res.sendFile(path.join(__dirname, 'public', 'index.html'));58});5960app.listen(PORT, '0.0.0.0', () => {61 console.log(`Server running on port ${PORT} (${isProduction ? 'production' : 'development'})`);62});Common mistakes when fixing CORS issues in Replit
Why it's a problem: Testing CORS with curl and assuming it works in the browser
How to avoid: CORS is a browser-only security feature. curl does not enforce CORS. Always test cross-origin requests in an actual browser with DevTools open.
Why it's a problem: Using credentials: true with origin: '*' in CORS config
How to avoid: Browsers reject wildcard origins when credentials (cookies, auth headers) are included. Specify exact origin URLs when credentials: true is set.
Why it's a problem: Adding CORS headers only to GET routes, forgetting about preflight OPTIONS requests
How to avoid: Use app.use(cors()) before your route definitions so the middleware handles OPTIONS preflight requests automatically for all routes.
Why it's a problem: Blaming the code when the Replshield 307 redirect is the actual cause
How to avoid: If CORS works in the workspace preview but fails intermittently in production, the Replshield redirect is likely stripping your headers. Combine frontend and backend in one Repl as the most reliable fix.
Why it's a problem: Using HTTP instead of HTTPS for cross-origin requests in production
How to avoid: Mixed HTTP/HTTPS requests are blocked by browsers. Ensure all URLs use HTTPS in production. Replit provides SSL automatically for deployed apps.
Best practices
- Deploy frontend and backend in the same Repl to avoid CORS entirely (same-origin architecture)
- Use the cors npm package instead of manually setting headers, as it handles preflight requests automatically
- Restrict allowed origins in production instead of using a wildcard (*)
- Always use HTTPS for deployed apps to prevent mixed-content CORS blocking
- Use .replit.dev domains instead of legacy .repl.co domains to reduce Replshield interference
- Test CORS after cold starts (15+ minute idle on Autoscale) to catch Replshield redirect issues
- Set up a development proxy (Vite or webpack) instead of enabling permissive CORS just for development
- Check the DevTools Network tab for OPTIONS preflight requests when debugging CORS failures
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
My Replit Express app works in the workspace preview but shows CORS errors when deployed. The error is: 'Access to XMLHttpRequest has been blocked by CORS policy: No Access-Control-Allow-Origin header is present.' I have the cors package installed. Could this be the Replshield 307 redirect issue? Show me the best solution for Replit deployments.
Fix the CORS errors in my project. My frontend and backend are in the same Repl. Configure Express to serve the static frontend files from the /public directory and handle API routes under /api. This should eliminate CORS by making everything same-origin. Also add the cors middleware as a fallback for any external clients.
Frequently asked questions
The Replit workspace preview and your app may run on the same origin or through a proxy that avoids CORS. In production, the deployed app URL is a different origin. Additionally, Replshield's 307 redirect can strip CORS headers on deployed apps.
Replshield is a Replit security service that adds a 307 Temporary Redirect to replshield.replit.dev on first requests to deployed apps. This redirect strips your custom CORS headers, causing the browser to block the response. It affects thousands of users and is a known platform-level issue since July 2025.
No. cors() with no options allows all origins, which means any website can call your API. In production, specify exact allowed origins using the origin option to prevent unauthorized access.
Yes, but it is not recommended. You would need to handle res.setHeader for multiple headers and manually respond to OPTIONS preflight requests. The cors package handles all of this automatically and correctly.
Yes. When the frontend is served by the same Express server as the API, all requests are same-origin. The browser never enforces CORS because there is no cross-origin request. This is the most reliable solution on Replit.
Yes. RapidDev can diagnose platform-specific CORS problems including Replshield interference, help restructure your project for same-origin architecture, and implement production-grade CORS configurations for complex multi-service setups.
Express apps with CORS middleware can produce 502 Bad Gateway errors on deployment. This usually means the server crashed or failed to start. Check the Console output and deployment logs for the underlying error. A 502 is not a CORS issue itself but may co-occur with CORS misconfiguration.
Use .replit.dev domains. The older .repl.co domains trigger more aggressive Replshield behavior. All new Replit deployments use .replit.app domains by default, which is the recommended choice.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation