localhost:5173 / dev-server-requests

How the Vite dev server handles requests to and from localhost:5173

Three settings cover three different requests: server.proxy forwards a request from 5173 to your backend, server.cors decides which origins may read a response from 5173, and server.allowedHosts decides which hostnames may reach 5173 at all.

Three requests, three settings

  • Your app on 5173 calls your backend — that is server.proxy.
  • Something on another origin calls 5173 — that is server.cors.
  • A request arrives under a hostname the server does not know — that is server.allowedHosts.

Read the error, not the guess

The three produce distinguishable errors, and the common mistake is to reach for CORS on all of them.

  • Blocked by CORS policy, in the browser console — the response came back without the header the browser wanted.
  • Blocked request. This host is not allowed. — a plain sentence from Vite, before your app ran.
  • 404 or an HTML page where JSON was expected — the request was never forwarded; the dev server answered it itself.

The proxy is usually the right answer

Forwarding /api through the dev server makes the request same-origin, and a same-origin request has no CORS problem to solve. That is why the proxy replaces the CORS question instead of answering it — the browser never sees a cross-origin call in the first place.

vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  }
}

What cors allows by default

The default is not open and not closed. Vite allows localhost, 127.0.0.1 and [::1] — on any port, over http or https — and rejects everything else. A second dev server on another localhost port is therefore allowed without configuration. A staging hostname is not.

default
server.cors = {
  origin: /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/
}

Why the default got stricter

An open dev server lets any page you visit read the files it serves, including your source. Narrowing the default origin closed that. Snippets from before the change set cors to true, which puts it back — if you copy one, you are copying the problem it was tightened against.

allowedHosts is not about origins

It reads the Host header, not the Origin header, and it runs before anything else. A request can be perfectly acceptable under your CORS settings and still be rejected here, because the two look at different parts of the same request. Tunnels and custom local domains hit this first.

Deciding in one pass

  • The call goes out to your own backend — proxy it, and stop there.
  • The call comes in from a page you control on another origin — widen cors for that origin only.
  • The request never gets that far and Vite answers with one sentence — add the hostname to allowedHosts.

# faq

Questions

Should I enable CORS or use the proxy?

Use the proxy for your own backend. It makes the request same-origin, so there is no CORS to configure.

Does server.cors affect requests my app makes?

No. It applies to requests other origins make to the dev server. Outgoing calls from your app are governed by the other server.

Why is my proxy returning HTML instead of JSON?

Because the path did not match the proxy rule, so the dev server handled it and returned the SPA fallback document.

Can allowedHosts cause a CORS error?

No. It rejects the request outright with a plain message before any CORS header is involved.

# next

Related

# sources

Checked against the Vite documentation on 2026-09-11.