localhost:5173 / open-browser
Making the Vite dev server open localhost:5173 in the browser automatically
Vite does not open a browser by default — set server.open to true in vite.config.js or start the server with --open, and pick the browser with the BROWSER environment variable rather than with the option itself.
Turn it on
The default is off. In the resolved server defaults open is false, so a plain npm run dev prints the URL and leaves it at that. Two ways to change it, and they do the same thing: the config option, or the CLI flag, which exists on both vite dev and vite preview.
export default {
server: {
open: true // default is false
}
}The string form is a path, not a browser name
This is the one that trips people up. Giving server.open a string does not name a browser — it names where in the app to land. Vite resolves it against the server URL with new URL(value, url), so a leading slash starts at the root and a bare segment resolves relative to the base. A full absolute URL replaces the address entirely, which is legal but rarely what was meant.
export default {
server: {
open: '/docs/index.html'
// -> http://localhost:5173/docs/index.html
}
}Which browser it picks, and how to change it
Not through the option. The dev server always calls its internal opener with the browser argument hard-set to true, which means the browser is read from the BROWSER environment variable and nowhere else. BROWSER_ARGS adds arguments, split on spaces. Both are read from a .env file as well, so a project can carry the preference without touching anyone’s shell.
$ BROWSER=firefox npm run dev -- --open # extra arguments, split on spaces $ BROWSER=firefox BROWSER_ARGS="--private-window" npm run dev -- --open
How do I keep it from opening anything?
Either drop the option, or set BROWSER to none. The check is an explicit string comparison after lowercasing, so none, NONE and None all work, and it wins even when open is true — useful when the flag comes from a script you do not control. A BROWSER value ending in .js is a third case: that file is run as a Node script with the current arguments plus the URL appended, and a non-zero exit prints a specific error.
- BROWSER=none — nothing opens, open: true is ignored.
- BROWSER=./scripts/open.js — the file runs as a Node script, URL as the last argument.
- That script exiting non-zero: "The script specified as BROWSER environment variable failed."
Which address gets opened when the server has several
The same list that gets printed at startup, picked by one rule. If server.host is a string, Vite takes the first resolved URL that contains that string — so pinning the host also pins what opens. Otherwise it takes the first Local URL, and only falls back to the first Network URL when there is no local one. With --host on a machine that has three interfaces, the browser still gets localhost.
if (typeof host === 'string') {
const matchedUrl = [...local, ...network].find((url) => url.includes(host))
if (matchedUrl) return matchedUrl
}
return resolvedUrls?.local[0] ?? resolvedUrls?.network[0]Why it does nothing in a container or over SSH
Because the opener is a child process spawned on the machine that runs Vite. Inside a container or on a remote box reached over SSH, that machine has no browser and no display, so the command either fails or opens nothing where you can see it. Vite does not crash over this — the error from the open call is logged and the server keeps running. Set BROWSER=none there and open the URL on your own machine instead.
# in a container: the flag is harmless but pointless $ BROWSER=none npm run dev -- --host ➜ Network: http://172.17.0.2:5173/ # open that from the host, with the port published
It opened once and never again after a restart
That is deliberate. The autostart is guarded by !isRestart, so a config change that restarts the dev server in place does not throw another tab at you. The server is running and reachable — only the opening step was skipped. Press o and enter in the terminal to open it manually; that shortcut runs the exact same code as the autostart, including the path from server.open.
await startServer(server, hostname, port)
if (httpServer) {
if (!isRestart && config.server.open) server.openBrowser()
}A request appears before the browser does
Reading the terminal or a proxy log with open enabled shows a request arriving a moment before any browser could have made it. That is Vite itself. When preTransformRequests is on, it fires an HTTP GET at the target URL with an Accept: text/html header while the browser is still starting, so static imports are already being crawled when the page arrives — the source puts the head start at around 500 ms. The response is discarded.
On macOS it reuses a tab, elsewhere it does not
Only on macOS, and only for a Chromium browser that is already running: Vite checks the process list and drives it with an AppleScript so an existing tab on the same URL gets reused instead of piling up. The list it matches against is fixed — Google Chrome and its Canary, Dev and Beta channels, Microsoft Edge, Brave, Vivaldi and Chromium. Everything else goes through the generic opener, which the source comments as always opening a new tab. One more macOS quirk: BROWSER=open is ignored rather than passed along, so it falls back to the system default browser.
- macOS + a listed Chromium browser already running: existing tab reused.
- Firefox, Safari, any browser not on that list, any other platform: new tab every start.
- No URL to open at all: Vite warns "No URL available to open in browser" and carries on.
# faq
Questions
Does Vite open the browser automatically?
Not by default. The resolved default for server.open is false. Set it to true in vite.config.js, or start the server with --open.
How do I open a specific page instead of the root?
Give server.open a string, such as "/docs/index.html". Vite resolves it against the server URL, so it is a path on the dev server, not a browser name.
How do I choose which browser opens?
With the BROWSER environment variable, not with server.open. BROWSER_ARGS adds arguments to it, split on spaces, and both can live in a .env file.
How do I stop Vite from opening a browser?
Remove the option, or set BROWSER=none. The value is compared case-insensitively and suppresses the browser even when open is true.
Why does --open do nothing in Docker or over SSH?
Because the browser process is spawned on the machine running Vite, which has no browser there. The failure is logged and the server keeps running — open the printed URL from your own machine.
Why did the browser not open after a restart?
The autostart is guarded by !isRestart, so an in-place restart skips it on purpose. Press o and enter in the terminal to open it manually.
Which URL does it open when several are printed?
The first Local URL, falling back to the first Network URL. If server.host is a string, the first resolved URL containing that string wins instead.
# next
Related
# sources
- Vite — server.open
- Vite source — openBrowser.ts (v8.3.0)
- Vite source — openBrowser() and server defaults in server/index.ts (v8.3.0)
- Vite source — getServerUrlByHost in utils.ts (v8.3.0)
- Vite source — CLI shortcuts, key o (v8.3.0)
- Vite — command line interface, --open
Checked against the Vite documentation on 2026-09-21.