No .output directory when building Tanstack Start for production
I had built my new Tanstack Start app that was in pre-release. I wanted to publish my new application on my ubuntu server running node. However, when I ran pnpm run build
it only created a dist folder with a server and a client folder in it.
Looking at the packages.json
file I instantly realized that this must be something wrong going on here since the start script referenced an output folder and looked like this:
"start": "node .output/server/index.mjs"
Huh, I don't have such an output folder. Only after quite a while and a lot of searching I did realize that this is because in the pre-release version of Tanstack. In the RC version I was using, Start’s prod build no longer bundles Nitro automatically. You now get a dist/ with a server bundle you must run behind your own server runtime (Node HTTP, Hono, Fastify, Bun, etc.). The server bundle exposes a Fetch-style handler you can call.
You can also use the nitro plugin and change the vite config like so:
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { defineConfig } from 'vite'
import viteReact from '@vitejs/plugin-react'
import { nitroV2Plugin } from '@tanstack/nitro-v2-vite-plugin'
export default defineConfig({
plugins: [
tanstackStart(),
nitroV2Plugin(/*
// nitro config goes here, e.g.
{ preset: 'node-server' }
*/),
viteReact(),
],
})
https://tanstack.com/start/latest/docs/framework/react/hosting#nitro
I simply ended up running my own server with hono though. I created a server.mjs
file in the apps root and pasted the following:
import { Hono } from 'hono'
import { serve } from '@hono/node-server'
import { serveStatic } from 'hono/serve-static.module'
import handler from './dist/server/server.js'
const app = new Hono()
// Serve built client assets (adjust the path as needed)
app.use('/assets/*', serveStatic({ root: './dist/client' }))
app.use('/favicon.ico', serveStatic({ root: './dist/client' }))
app.use('/', serveStatic({ root: './dist/client', index: 'index.html' }))
// Let TanStack Start handle everything else (server routes, SSR, server functions)
app.all('*', c => handler.fetch(c.req.raw))
serve({ fetch: app.fetch, port: Number(process.env.PORT) || 3000 })
Then simply update the packages.json
file accordingly:
{
"scripts": {
"start": "node server.mjs"
}
}
Now you should be ready to host your node application!