serve -C (--cors): enable CORS on the Vercel serve static server
- tool
- CORS
- command
- serve
- flag
- -C, --cors
- default
- off (no Access-Control-* headers are sent)
npx serve -C ./build (long form --cors) makes Vercel's serve static file server add CORS headers to every response: Access-Control-Allow-Origin: *, Access-Control-Allow-Headers: *, Access-Control-Allow-Credentials: true and Access-Control-Allow-Private-Network: true. That lets a front end on another port or host fetch the files during development. Without -C, no CORS headers are sent and cross-origin reads are blocked by the browser.
The headers serve sends
A local serve instance with --cors, a cross-origin GET and a preflight (-L turns off request logging, -n the clipboard copy):
npm init -y >/dev/null && npm install --silent --no-audit --no-fund serve@14.2.6 >/dev/null 2>&1
mkdir site && echo '{"ok":true}' > site/data.json
timeout 12 node node_modules/serve/build/main.js site -l tcp://127.0.0.1:5418 -L -n >/dev/null 2>&1 &
timeout 12 node node_modules/serve/build/main.js site -l tcp://127.0.0.1:5420 -L -n --cors >/dev/null 2>&1 &
sleep 4
echo "--- without --cors:"
curl -s -D - -o /dev/null -H "Origin: http://localhost:3000" http://127.0.0.1:5418/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control"
echo "--- with --cors:"
curl -s -D - -o /dev/null -H "Origin: http://localhost:3000" http://127.0.0.1:5420/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control"
echo "--- preflight with --cors:"
curl -s -D - -o /dev/null -X OPTIONS -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: X-Api-Version" http://127.0.0.1:5420/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control"
waitOutput
--- without --cors: HTTP/1.1 200 OK --- with --cors: HTTP/1.1 200 OK Access-Control-Allow-Origin: * Access-Control-Allow-Headers: * Access-Control-Allow-Credentials: true Access-Control-Allow-Private-Network: true --- preflight with --cors: HTTP/1.1 200 OK Access-Control-Allow-Origin: * Access-Control-Allow-Headers: * Access-Control-Allow-Credentials: true Access-Control-Allow-Private-Network: true
The preflight gets a 200 OK with the same four headers: serve treats OPTIONS like a normal request for static files.
What the headers mean
| Header | Value | Effect |
|---|---|---|
| Access-Control-Allow-Origin | * | Any origin may read responses fetched without credentials |
| Access-Control-Allow-Headers | * | Any request header passes the preflight (for requests without credentials) |
| Access-Control-Allow-Credentials | true | Has no effect together with the wildcard origin, see below |
| Access-Control-Allow-Private-Network | true | Answers Private Network Access preflights from public pages to a local server |
The credentials pitfall
Access-Control-Allow-Credentials: true suggests that cookies work, but the Fetch standard forbids combining credentials with Access-Control-Allow-Origin: *. A fetch(url, { credentials: 'include' }) from another origin is therefore blocked, and the console reports the wildcard problem described on wildcard origin with credentials. Requests without credentials, which is what most static assets use, work normally.
If you need cookies or a fixed origin, set the headers yourself in serve.json:
{
"headers": [
{
"source": "**/*.json",
"headers": [
{ "key": "Access-Control-Allow-Origin", "value": "http://localhost:3000" },
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
{ "key": "Vary", "value": "Origin" }
]
}
]
}Compared with other dev servers
| Server and option | Allow-Origin | Credentials usable |
|---|---|---|
| serve -C | * | No (wildcard) |
| http-server --cors | * | No; no credentials header at all |
| live-server --cors | Echoes the request Origin | Yes |
For http-server see http-server --cors; for the general mechanism, the preflight request page.
FAQ
Does serve --cors let me send cookies cross-origin?
No, although it sends Access-Control-Allow-Credentials: true. The origin is the wildcard *, and browsers refuse credentialed responses whose allowed origin is *. Cookies only work when the server echoes the exact origin.
Can I configure CORS headers in serve.json instead?
Yes. The headers setting in serve.json (handled by serve-handler) adds arbitrary response headers per path glob, which lets you send a specific Access-Control-Allow-Origin value instead of the wildcard.
Why does serve answer OPTIONS with 200 and the file?
serve 14 treats OPTIONS like GET for static files. The CORS headers are present, so a browser preflight succeeds; the extra body is ignored.