Skip to main content

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.jsonfile accordingly:

{
  "scripts": {
    "start": "node server.mjs"
  }
}

Now you should be ready to host your node application!