I’ve been debugging this for several days, trying different deployment variations. My simple test full-stack app behaves as follows:
- it works fine when the backend server runs locally + frontend runs locally,
- it works fine when I run the backend locally with the frontend deployed on Netlify,
- when the backend deployed on render, and the frontend either run locally on from Netlify I am getting CORS error: has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled. The request is 200, but blocked by CORS.
I don’t know what else I could do at this point. I use the cors package with some super basic configurations, yet this CORS error persists.
All env variables are triple-checked and properly added.
Below is my server.js
file code:
const express = require("express");
const { initializeApp } = require("firebase/app");
const { getStorage, ref, getDownloadURL } = require("firebase/storage");
const cors = require("cors");
const dotenv = require("dotenv");
dotenv.config();
const app = express();
const allowedOrigins =
process.env.NODE_ENV === "development"
? ["http://localhost:5173"]
: [process.env.FRONTEND_URL];
app.use(
cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
return callback(null, true);
}
callback(new Error("BE Error: Blocked by CORS policy"));
},
})
);
const firebaseConfig = {
apiKey: process.env.FIREBASE_API_KEY,
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
projectId: process.env.FIREBASE_PROJECT_ID,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.FIREBASE_APP_ID,
};
const firebaseApp = initializeApp(firebaseConfig);
const storage = getStorage(firebaseApp);
app.get("/api/image-url", async (req, res) => {
const { path } = req.query;
if (!path) {
return res.status(400).send("Path is required");
}
try {
const storageRef = ref(storage, path);
const downloadUrl = await getDownloadURL(storageRef);
return res.json({ url: downloadUrl });
} catch (error) {
console.error("Error fetching image URL:", error);
return res.status(500).send("Failed to fetch image URL");
}
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on port: ${port}`);
});
I am fetching images stored on Firebase, FE fetch request calling the backend, and the backend is calling the Firebase.
React Vite FE portion:
const baseUrl =
import.meta.env.MODE === "development"
? "http://localhost:3000"
: import.meta.env.VITE_BACKEND_URL;
const getImageUrl = async ({ path }: { path: string }) => {
try {
const response = await fetch(`${baseUrl}/api/image-url?path=${path}`);
if (!response.ok) {
throw new Error("Failed to fetch image URL");
}
const data = await response.json();
return data.url;
} catch (e) {
console.log("Error fetching images FE: error is", e);
throw new Error("Error fetching images FE");
}
};
export { getImageUrl };
2
Answers
I made a mistake by incorrectly defining the script to run the server.js file in package.json. As a result, it was running an old build from the dist folder instead of running server.js file directly: INCORRECT:
CORRECT:
Since I'm note using build, dist content is outdated and not used. Directly running server.js file solves the CORS issue!
To fix the CORS issue in your Node/Express app deployed on Render:
Check
allowedOrigins
: Ensureprocess.env.FRONTEND_URL
is set correctly for production (e.g.,https://your-netlify-site.netlify.app
).Add Preflight Handling: Add this to handle OPTIONS requests:
Test with Wildcard: Temporarily allow all origins for debugging:
Ensure Correct Fetch Settings: Use
mode: 'cors'
in your fetch request:Check Render CORS Settings: Make sure Render is not overriding your CORS settings.
Check Response Headers: Ensure
Access-Control-Allow-Origin
is set in the response headers.Test locally if the issue persists and check Render logs for errors.