I'm trying to consume my own Node.js/Express API from a frontend application, but I'm getting a CORS error that I couldn't solve.
Context:
- Backend: Node.js + Express
- Deployment: Vercel (
@vercel/node) - Frontend: hosted on
https://www.linkgrid.site - API URL:
https://linkgrid-api.vercel.app/api/users/create
The error I get
Access to XMLHttpRequest at 'https://linkgrid-api.vercel.app/api/users/create' from origin 'https://www.linkgrid.site' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have:
- Configured
corsmiddleware on Express. - Added CORS-related headers in
vercel.json. - Tried different combinations of allowed origins and headers.
- Confirmed that both frontend and backend are correctly deployed.
vercel.json:
{
"version": 2,
"builds": [
{
"src": "dist/server.js",
"use": "@vercel/node",
"config": { "includeFiles": ["dist/**"] }
}
],
"routes": [
{
"src": "/(.*)",
"dest": "dist/server.js",
"headers": {
"Access-Control-Allow-Origin": "https://linkgrid.site",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS,PATCH",
"Access-Control-Allow-Headers": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Max-Age": "86400"
}
}
]
}
app.ts:
export const app = express();
app.use(
cors({
origin: [
"https://linkgrid.site",
"https://www.linkgrid.site",
"https://linkgrid.vercel.app",
...(process.env.NODE_ENV === "development" ? ["http://localhost:3000"] : []),
],
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
allowedHeaders: [
"Content-Type",
"Authorization",
"X-Requested-With",
"Accept",
"Origin"
],
exposedHeaders: ["Content-Range", "X-Content-Range"],
credentials: true,
maxAge: 86400,
preflightContinue: false,
optionsSuccessStatus: 204
})
);
app.options("*", cors());
app.use(
helmet({
crossOriginResourcePolicy: { policy: "cross-origin" },
crossOriginOpenerPolicy: { policy: "same-origin" }
})
);
app.use(express.json());
app.use(limiter);
app.use("/api/users", userRouter);
app.use("/api/links", linkRouter);
app.use(errorMiddleware);
Even after configuring both cors in Express and setting the proper CORS headers in vercel.json, why am I still getting this preflight CORS error? Both backend and Vercel config seem correct to me.