Serving in production via Bun
What is the right way to serve the application in production via Bun in the new RC?
Should we write our own handler with Bun.serve() now?
88 Replies
firm-tan•3mo ago
you certainly can yes
foreign-sapphire•3mo ago
please do it!!!
flat-fuchsia•3mo ago
flat-fuchsia•3mo ago
works in both dev and prod
unfortunately Vite can't be ran in middleware mode with Bun.serve (it can only work with express, fastify, or polka, that i know of)
so we have to run the vite server, and proxy the asset requests to it
firm-tan•3mo ago
or just not use bun during dev
only in prod
flat-fuchsia•3mo ago
yes, but that's only if you dont have some kind of instrumentation. like migrations running on server startup
arguably this could be ran as a separate process
by the way, i feel like example server.ts files such as this one and an express one should be added to the hosting docs, because this is non-trivial
what do you think ?
firm-tan•3mo ago
we should add complete examples
we have a start-bare example
we should add one of those for each express/bun/...
contributions welcome!
flat-fuchsia•3mo ago
ill try pushing something later this week if not done already by that point
foreign-sapphire•3mo ago
GitHub
router/docs/router/framework/react/how-to/setup-ssr.md at main · T...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
foreign-sapphire•3mo ago
@notKamui this as reference ?
flat-fuchsia•3mo ago
GitHub
router/docs/router/framework/react/how-to/setup-ssr.md at main · T...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
flat-fuchsia•3mo ago
this in particular yes
but it has manual things that don't need to be done with start
this can be simpler
foreign-sapphire•3mo ago
did you checked that => https://github.com/honojs/vite-plugins/blob/main/packages/dev-server/README.md
GitHub
vite-plugins/packages/dev-server/README.md at main · honojs/vite-p...
Vite Plugins for Hono. Contribute to honojs/vite-plugins development by creating an account on GitHub.
foreign-sapphire•3mo ago
that is a Vide Dev server using Hono
foreign-sapphire•3mo ago

flat-fuchsia•3mo ago
here's an express one (prod only)
reduced to the simplest
ill check that out
foreign-sapphire•3mo ago
GitHub
vite-plugins/packages/dev-server/src/dev-server.ts at main · honoj...
Vite Plugins for Hono. Contribute to honojs/vite-plugins development by creating an account on GitHub.
foreign-sapphire•3mo ago
this is the main file
other-emeraldOP•3mo ago
Just spent some time optimizing our production server with Bun and the results are pretty sweet. Pre-loading all static assets into memory on startup = no file system hits during requests.
Was dealing with slow static file serving in our TanStack Start app, so built this approach that loads everything into memory once and serves from there. The difference is noticeable.
other-emeraldOP•3mo ago
other-emeraldOP•3mo ago
The neat part is using Bun's native file.type for MIME types instead of maintaining a huge lookup table. Also discovered that
readdir with recursive: true is way cleaner than writing a custom directory walker.
Running this in production now and it's handling everything smoothly. Memory usage is predictable since everything loads once at startup. Good for when you know your static assets won't exceed available RAM.
Anyone else doing something similar with Bun? Curious about other approaches to static file serving optimization.other-emerald•3mo ago
is this a known issue they are working on?
flat-fuchsia•3mo ago
it's not really an "issue" per se, it's just that vite middlewares support a specific shape that bun.serve doesnt. Once bun.serve has middleware support, it'll probably work. I think they're aware of the need
that's insanely good
i'll probably steal this even
other-emeraldOP•3mo ago
Do it 😉
flat-fuchsia•3mo ago
did you start from scratch or from my version btw ?
other-emeraldOP•3mo ago
Started from scratch, but looked at your version before. What bugged me was, that you didnt dynamically load the static client assets.
I justed tested the deployment in production. Even shaved of like 7ms of the ssr response this way.
other-emerald•3mo ago
Does the way you have it setup work with ETags?
other-emeraldOP•3mo ago
Yes, because the static assets are served as routes Bun.serve() automatically creates ETags

xenial-black•3mo ago
Just to put my two cents in, I went with a "simplest possible" SSR entry-point, rather than fastest:
- ✅ Runs on Node / Bun / Deno with no changes required
- ✅ No new dependencies.
srvx is already used by tanstack-start
- ✅ Dead simple. Just vite build, then node server.js
- ❌ Slower than @Magnus's solution aboveother-emeraldOP•3mo ago
Bun
HTTP server – API | Bun Docs
Bun implements a fast HTTP server built on Request/Response objects, along with supporting node:http APIs.
other-emerald•3mo ago
right I was just asking cause you manually set the expiry date which seemed weird
and I thought it might have messed with them
but that's cool it doesn't I may also nab this
other-emeraldOP•3mo ago
Awesome. Seems like a good starting point for everyone.
This needs to be on the documentation.
xenial-black•3mo ago
100% agree. Not sure what the best way to contribute this is. Should I raise an issue on the repo first?
rising-crimson•3mo ago
works on cloudflare?
flat-fuchsia•3mo ago
you could probably just open a PR
and edit the hosting docs
this should be extended to have a way to ignore big assets that would fill the RAM, but still have dynamic routes to them
and it would be perfect
xenial-black•3mo ago
I wouldn't expect so, no. The srvx is designed for long running processes (like a hosted docker container). Cloudflare is designed for "handle request and then die"
flat-fuchsia•3mo ago
flat-fuchsia•3mo ago
@Magnus i extended your bun server a bit to support file inclusion/exclusion as well as size thresholds
included files are loaded in RAM, skipped files are lazy loaded but the routes are static
equal-jade•3mo ago
This worked but two things I had to change was to name file as
server.ts and I had to install srvx separately. So that means tanstack-start no longer comes with it?
For me the issue was npm run start itself was failing so I had to create this custom server file to make it work. I am trying to make sense of which internal thing is missing in tanstack start as this should have been working out of the box.firm-tan•3mo ago
@Magnus can you both please create an example and document this?
xenial-black•3mo ago
What version of
@tanstack/react-start do you have installed?
This is my npm why output for srvx:
equal-jade•3mo ago
Same as you. Infact my output is also same as you but for some reason I have to install it separately only then it works otherwise I get ERR_MODULE_NOT_FOUND.
ratty-blush•3mo ago
@Siddharth Pant are you using pnpm?
equal-jade•3mo ago
You got it right. The project I was testing was in pnpm. I created a fresh project with npm and the file worked without extra install. So with pnpm you have to do an explicit install even if package is present as a dependency. Will keep a note about that.
ratty-blush•3mo ago
Yeah pnpm has a different way to manage dependencies
flat-fuchsia•3mo ago
as in a repo, or a sandbox to add to the docs in the examples section ?
firm-tan•3mo ago
both
however a codesandbox won't work I guess with bun?
flat-fuchsia•3mo ago
ah no, it won't :/
firm-tan•3mo ago
well then just add an example to the repo and we will link to it
foreign-sapphire•3mo ago
@Magnus , @notKamui and @marksfrancis amazing work!!! When have some link please put there I want read that 🙂
flat-fuchsia•3mo ago
sure thing
other-emeraldOP•3mo ago
Yeah, will look into it now 🫡
other-emeraldOP•3mo ago
@Manuel Schiller @notKamui I created a pull request.
https://github.com/TanStack/router/pull/5237
GitHub
docs: add Bun production server guide for TanStack Start by magnusm...
Description
This PR enhances the Bun deployment documentation for TanStack Start by adding information about a
production-ready server implementation.
Problem
The current documentation suggests run...
other-emeraldOP•3mo ago
@notKamui thanks for the improvements! I implemented them and fixed the remaining type / eslint errors and created this demo repo: https://github.com/magnusmay/tanstack-start-bun-hosting
GitHub
GitHub - magnusmay/tanstack-start-bun-hosting
Contribute to magnusmay/tanstack-start-bun-hosting development by creating an account on GitHub.
flat-fuchsia•3mo ago
masterclass
other-emeraldOP•3mo ago
LFG! My first opensource contribution. Feels good man
other-emerald•3mo ago
Switching to bun for this, good work
xenial-black•3mo ago
This is the setup I use. It's just plain npm and node
https://github.com/MarkSFrancis/ts-react-template/blob/main/server.js
GitHub
ts-react-template/server.js at main · MarkSFrancis/ts-react-template
Template project for a Typescript react app. Contribute to MarkSFrancis/ts-react-template development by creating an account on GitHub.
firm-tan•3mo ago
thanks! can you please move that example within the router monorepo (under examples/react/start-bun) and then reference this in the docs?
other-emeraldOP•3mo ago
Done 🙂
flat-fuchsia•3mo ago
i have a suggestion: instead of using node (readdir, join), you can use bun's apis fully
bun handles windows' paths for you too
it seems chrome is the one generating the etags :ThinkPlot: because when requesting the asset via postman or curl, no etag show up in the headers
im working on that + actual gzipping
flat-fuchsia•3mo ago
@Magnus May here's my new version (you can still remove the migration stuff)
flat-fuchsia•3mo ago
several things:
- dyn import everything to keeps things no loaded in RAM if not needed anymore
- added explicit ETag generation (disableable)
- gzip compression for assets bigger than a threshold (disableable)
i added it as a comment to the PR, to find it more easily
equal-jade•3mo ago
node LTS v22.18+ has
--experimental-strip-types turned on by default so you don't need that flag anymore in your package.jsonother-emeraldOP•3mo ago
Very nice, I added it to the PR
Thanks for the work
That was a very good idea
flat-fuchsia•3mo ago
im working on a vite plugin that has a dx similar to the output nitro produces
+ before/after start hooks
flat-fuchsia•3mo ago
api looks like this

firm-tan•3mo ago
not sure if this was mentioned anywhere here but you can use nitro with bun and start
flat-fuchsia•3mo ago
beforeStartHooks is an array of module names to run before server start
i've dabbled with it, but had issues (reported to nitro)
nitro does too much for me anyway
firm-tan•3mo ago
fair enough
flat-fuchsia•3mo ago

flat-fuchsia•3mo ago
the resulting dist looks like this
entrypoint.js is basically @Magnus May's bun serve file, with the hooks plugged in
(the plugin is omega overengineered, even if the output is lean; this is most likely nonsense and the standalone serve.ts file is fine)
flat-fuchsia•3mo ago
@Magnus May this points to nothing (404)

flat-fuchsia•3mo ago
same for the server.ts link
other-emerald•3mo ago
is this available anywhere yet?
flat-fuchsia•2mo ago
ill push this in a few hours or so, will ping you
it's not perfect, and i won't use it because i do think having a server.ts at the root is plenty fine
+ i use docker to build anyway, so i can easily bundle what i want
other-emerald•2mo ago
Ah
I do need to switch to docker builds
correct-apricot•2mo ago
In the Bun server examples, there's definitely an issue constructing the static routes for assets that work on Windows.
filepath will resolve to something like dist/client\assets\index-CYVUvHau.js which is fine (Windows accepts either path separator and Bun fill read the file just fine). However, route will resolve into /assets\index-CYVUvHau.js, where the windows path separator \ won't match how the route will be requested over HTTP (/assets/index-CYVUvHau.js).
If you change to something like
then you'll be creating routes that have the expected POSIX-path matching names for the Bun server, so all your static assets under the assets and other subfolders will now work.
(That path change might be brittle, just meant as an example)firm-tan•2mo ago
PR welcome to the examples!
correct-apricot•2mo ago
Submitted! https://github.com/TanStack/router/pull/5285
GitHub
Fix Bun server static routes from using the wrong path separator on...
The issue on Windows:
filepath will resolve to something like dist/client\assets\index-CYVUvHau.js, which is fine (Windows accepts either path separator and Bun fill read the file just fine).
rout...
adverse-sapphire•2mo ago
hey, when trying the start-bun example and building using
bun run build im not receiving any .html files in the dist/ folder, is that normal? this results in the server returning a 404flat-fuchsia•2mo ago
GitHub
miniverso/plugins/bunServer at start-server-plugin · notKamui/mini...
Self-hostable grouping of mini web applications for everyday use - notKamui/miniverso
adverse-sapphire•2mo ago
hi, has anyone tried to deploy this using a bun-docker container?
continuing-cyan•2mo ago
I have this Dockerfile set up currently. Note that the "server.js" is compiled to dist in the "bun run build" command separately from the rest. I can show you that too if you need.
Second note is that I use Prisma too so you might not need the prisma engine that I have.
adverse-sapphire•2mo ago
thank you so much, i would love to see how you build the
server.jscontinuing-cyan•2mo ago
It's a really simple bun command right in package.json
"build:server": "bun build server.ts --outfile dist/server.js --target=bun --format=cjs --minify",
The reason for doing format cjs is only because I deploy it to google cloud run and I had some issues with GRPC (I think). You can probably leave that out or customize as you please.foreign-sapphire•2mo ago
can you provide a github repo ?
continuing-cyan•2mo ago
For the cjs?
I only have a private repo right now.
This is the error that I am getting (note that the js file is production-server.js not server.js but that is just a renaming of the same file). This file is copied from the hosting docs for bun.
This issue pointed me in the direction of setting
cjs. So I dont think it has anything to do with the RC per se.
https://github.com/oven-sh/bun/issues/9367