Skip to content

/flags/cors/serve-cors

serve -C (--cors): enable CORS on the Vercel serve static server

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
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):

bash
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"
wait

Output

--- 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

HeaderValueEffect
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-CredentialstrueHas no effect together with the wildcard origin, see below
Access-Control-Allow-Private-NetworktrueAnswers 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:

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 optionAllow-OriginCredentials usable
serve -C*No (wildcard)
http-server --cors*No; no credentials header at all
live-server --corsEchoes the request OriginYes

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.

Sources