CORS
The browser does not let JavaScript on one site's page read responses from a server at another address unless the server explicitly allows it. The permission mechanism is called CORS (Cross-Origin Resource Sharing). If the blog's frontend runs on http://localhost:5173 and the API on http://localhost:3000, the browser blocks the requests without CORS.
What the problem looks like
Open the frontend page and run a request to the API in the browser console:
// browser console on http://localhost:5173
const response = await fetch('http://localhost:3000/posts');
console.log(await response.json());The console shows an error with the words "blocked by CORS policy". The server did receive the request and answer — it is the browser that blocks it. curl and other servers do not check CORS.
Installing
npm install @fastify/corsRegistering
Allow requests from the frontend address in src/app.js:
// src/app.js
import cors from '@fastify/cors';
app.register(cors, {
origin: 'http://localhost:5173',
});Repeat the request in the console — now the list of posts is printed. The plugin adds the Access-Control-Allow-Origin header to replies, which tells the browser that reading is allowed.
Methods and headers
Before PUT, DELETE and requests with an Authorization header, the browser first sends an OPTIONS preflight request. The plugin answers it, but it is better to list the allowed methods explicitly:
// src/app.js
app.register(cors, {
origin: ['http://localhost:5173', 'https://blog.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
});Now the frontend, both on the local address and on the production domain, can create and delete posts with a token.
Main options
| Option | What it sets |
|---|---|
origin | Allowed addresses: a string, an array or true for any |
methods | Allowed HTTP methods |
allowedHeaders | Headers the client may send |
credentials | Allow sending cookies |
maxAge | How many seconds the browser remembers the OPTIONS answer |
It is convenient to keep the addresses in .env so the real domain can be set on the server.
Common mistake
origin: true or '*' lets any site read the API. That is fine for a public API, but if the API works with tokens or cookies, list only your own addresses — otherwise a foreign page can send requests on behalf of your users.