How to Fix CORS Errors in Node.js Fastify
Cross‑Origin Resource Sharing (CORS) errors are one of the most common roadblocks when building APIs with Fastify. This guide walks you through the root causes, provides a solid Fastify‑compatible solution, and shows you how to test it locally and in production.
Why CORS Errors Occur
When a browser requests a resource from a different origin (scheme, host, or port) than the one serving the page, the server must explicitly allow that request via CORS headers. If the headers are missing or malformed, the browser blocks the response and logs an error such as:
Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Fastify does not add CORS headers automatically; you have to enable them via a plugin.
Step‑by‑Step Fix Using fastify-cors
1️⃣ Install the official plugin
npm install fastify-cors
2️⃣ Register the plugin with appropriate options
// server.js
const fastify = require('fastify')({ logger: true })
// Enable CORS for all origins (development only)
fastify.register(require('fastify-cors'), {
origin: '*', // <- allow any origin
methods: ['GET','POST','PUT','DELETE','OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
})
fastify.get('/ping', async (request, reply) => {
return { msg: 'pong' }
})
fastify.listen({ port: 3000 }, err => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
fastify.log.info('Server listening on http://localhost:3000')
})
Tip: In production replace
origin: '*'with a whitelist array, e.g.,origin: ['https://app.example.com'].
3️⃣ Verify the headers locally
curl -i -X GET http://localhost:3000/ping
You should see:
HTTP/1.1 200 OK
access-control-allow-origin: *
access-control-allow-credentials: true
content-type: application/json; charset=utf-8
...
4️⃣ Test from the browser
Create a simple HTML file:
<!DOCTYPE html>
<html>
<head><title>CORS Test</title></head>
<body>
<script>
fetch('http://localhost:3000/ping')
.then(r => r.json())
.then(console.log)
.catch(console.error)
</script>
</body>
</html>
Open it in Chrome; the console should log {msg:"pong"} without any CORS warnings.
Advanced Scenarios
✅ Pre‑flight Requests (OPTIONS)
For non‑simple requests (e.g., custom headers or methods other than GET/POST), browsers send an OPTIONS pre‑flight. Fastify‑cors handles this automatically, but you can customize the response:
fastify.register(require('fastify-cors'), {
preflightContinue: false,
optionsSuccessStatus: 204
})
🔐 Credentialed Requests
When credentials: true is set, you must not use origin: '*'. Instead specify exact origins:
fastify.register(require('fastify-cors'), {
origin: ['https://dashboard.example.com'],
credentials: true
})
🛡️ Security Hardening
- Limit allowed methods to only those you expose.
- Restrict headers to the minimal set needed.
-
Enable rate‑limiting (e.g.,
fastify-rate-limit) to mitigate abuse.
Common Pitfalls & Debugging Tips
| Symptom | Likely Cause | Fix |
|---|---|---|
CORS header ‘Access-Control-Allow-Origin’ missing |
Plugin not registered or placed after route definitions | Register fastify-cors before any routes. |
Preflight response is 404 |
No OPTIONS handler – ensure fastify-cors is loaded. |
|
Credentials blocked |
Using origin: '*' with credentials: true. |
Set explicit origin list. |
| Still blocked after changes | Browser cache – clear or use incognito. |
Use fastify.log.info(request.headers.origin) inside a route to inspect the incoming origin when troubleshooting.
Deploying to Production (Docker Example)
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
CMD ["node", "server.js"]
Build and run:
docker build -t fastify‑api .
docker run -p 8080:8080 fastify‑api
Make sure the CORS configuration matches your production domain.
Quick Recap
- Install fastify-cors.
- Register it before routes.
- Use explicit origins in production.
- Test both simple and pre‑flight requests.
- Harden the policy for security.
Resources & Tools
- Fastify docs: https://www.fastify.io/docs/latest/Guide/
- CORS spec: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- Online CORS tester: https://www.test-cors.org/
Get the Ready‑Made Fix
If you prefer a plug‑and‑play solution, you can download a pre‑configured Fastify starter that already includes a robust CORS setup:
Happy coding!
Top comments (0)