localhost:5173 / vite-proxy
Proxying API requests from the Vite dev server
server.proxy forwards any request whose path starts with a given prefix to another server, so the browser only ever talks to localhost:5173 and no CORS error appears.
The shortest version
Every request starting with /api goes to the backend. The browser still sees a same-origin request, because as far as it knows everything came from 5173.
export default defineConfig({
server: {
proxy: {
'/api': 'http://localhost:8080',
},
},
})Why this instead of fixing CORS
Because there is nothing to fix. The cross-origin request never happens — the browser talks to 5173, and 5173 talks to the backend server-side, where the same-origin policy does not apply. Loosening CORS on the backend to make local development work is how test settings end up in production.
When the backend does not want the prefix
rewrite strips it. This is the option people usually discover after twenty minutes of 404s from an API that works fine in curl.
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
}changeOrigin, in one sentence
It rewrites the Host header to the target instead of passing localhost:5173 through. Needed whenever the backend routes by hostname — virtual hosts, most hosted APIs, anything behind a shared ingress.
WebSockets
Socket connections need to be declared, otherwise only the HTTP upgrade request gets proxied and the socket dies immediately.
proxy: {
'/socket': {
target: 'ws://localhost:8080',
ws: true,
},
}Regex keys
A key beginning with ^ is treated as a regular expression instead of a path prefix.
proxy: {
'^/(api|auth)/.*': {
target: 'http://localhost:8080',
changeOrigin: true,
},
}Two things that quietly break it
- A non-relative base: every proxy key has to carry that base as a prefix, or nothing matches.
- Proxied requests skip Vite entirely — no transform, no HMR. That is intended, but it means a path you proxy can never also be served by Vite.
Preview has its own proxy
preview.proxy defaults to server.proxy but is a separate option. If the API works on 5173 and 404s on 4173, check that one.
# faq
Questions
Does the proxy remove the path prefix automatically?
No. /api is forwarded as /api unless you add a rewrite.
When do I need changeOrigin?
When the target routes by Host header — virtual hosts and most hosted APIs.
Does the proxy work for WebSockets?
Yes, with ws: true on that entry.
Why does the proxy work in dev but not in the build?
It is a dev server feature. A built site has no proxy — that job belongs to whatever serves it.
# next
Related
# sources
Checked against the Vite documentation on 2026-09-11.