Deployments
Bun
Develop, build and run a VitNode app or API on Bun instead of Node.js - TanStack Start through Nitro's bun preset, and Hono on Bun.serve.
VitNode runs on Bun from the first dev to production. The TanStack Start app runs Vite on Bun and builds with Nitro's bun preset, and a standalone Hono API runs its TypeScript straight on Bun.serve - no compile step. Same app, same plugins, one runtime fewer to install on the server.
Before you begin
- Bun installed on your machine and on the server. Node.js is optional: when it is missing,
bun runstands in for it, so thevitnodeCLI still runs. - A PostgreSQL database, as for any VitNode deployment.
Create a Bun app
Answer Bun to "Where to deploy?" when you create the app. The option shows up only when Bun is installed, and it is the default when you pick Bun as the package manager.
bun create vitnode-app@canary --deploy bunAny package manager can install the packages; the runtime is a separate choice. Here is what the generator changes compared with a Node app:
| Where | Node app | Bun app |
|---|---|---|
App dev / build | vitnode dev, vitnode build | bun --bun vitnode dev, bun --bun vitnode build |
App vite.config.ts | Nitro's default Node server | nitro: { preset: "bun" } |
| API entry | @hono/node-server and ws | export default { fetch, websocket } with hono/bun |
API build | tsc into dist | none - Bun runs src/index.ts |
package.json | "vitnode": { "runtime": "node" } | "vitnode": { "runtime": "bun" } |
start stays vitnode start in both. It reads the build's preset (or the API's vitnode.runtime) and starts the server with Bun or Node to match.
Move an existing app to Bun
Build the app for Bun
Set Nitro's preset in the app's vite.config.ts:
vitnode({
nitro: {
preset: 'bun',
rollupConfig: { external: [/^@sentry\//] },
},
webSocket: true,
})Run Vite on Bun
Prefix the app's dev and build scripts with bun --bun, so Vite and the SSR code run on Bun rather than on Node:
{
"scripts": {
"dev": "bun --bun vitnode dev",
"build": "bun --bun vitnode build",
"start": "vitnode start"
},
"vitnode": { "runtime": "bun" }
}Serve a standalone API with Bun
Skip this step for a single app - its API is part of the build above.
A standalone API exports Bun's server object instead of calling serve from @hono/node-server. Copy the WebSocket route for Bun, drop the API's build script and set "vitnode": { "runtime": "bun" } in its package.json. vitnode dev then runs bun --hot src/index.ts and vitnode start runs bun src/index.ts. You can remove @hono/node-server and add @types/bun to devDependencies.
Build and run
Deploy exactly as in Self-hosted, with the same four commands:
bun install --frozen-lockfile
bun run build
bun run db:migrate
bun startBun loads .env before your code starts, so every variable in it applies -
even one you forgot about. A REDIS_URL pointing at a Redis that isn't
running makes WebSocket handshakes answer 503 until Redis is up. Comment out
what you don't use.
Check the result
vitnode start prints Running once the server accepts connections. To be sure it is Bun answering, list the processes: the server shows up as bun .output/server/index.mjs for an app, or bun src/index.ts for an API.