Blog · Deploy guides
How to deploy a TanStack Start app in 2026: Nitro, a start script and one command
You have a TanStack Start app, and you want it on a Node server at an address with HTTPS. TanStack's hosting guide asks two things of the app for that: the Nitro plugin, and a start script. With both in place, pethost deploy writes the Dockerfile, builds the app and prints its address. The app the TanStack CLI creates was built and started in 29 seconds the first time.
- Two things in the app: the Nitro plugin, which
--deployment nitroadds when the app is created, and"start": "node .output/server/index.mjs"inpackage.json. - One command:
pethost deployin the folder that haspackage.json. It writes a Dockerfile that runsnpm run buildand thennpm run start. - The port: the Nitro server listens on 3000. Pethost finds that and sends the address there, over HTTPS.
- A build that fails changes nothing: the version before keeps running, and the screen shows the build's error.
- The price: €9.99 a month for a machine of 2 vCPU, 3 GB and 30 GB that runs this app and every other project you have. There is no free tier.
What you need to deploy a TanStack Start app in 2026
Three things: the app, the pethost command and a Pethost account.
The app here is the one the TanStack CLI creates, with Nitro as its deployment target:
npx @tanstack/cli@latest create my-app --deployment nitro
The flag adds the Nitro plugin to vite.config.ts. In an app you already have, add it as the hosting guide's Nitro part says:
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { defineConfig } from 'vite'
import { nitro } from 'nitro/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [tanstackStart(), nitro(), viteReact()],
})
Then give package.json the script that starts what the build writes. The CLI leaves build there and no start:
"scripts": {
"dev": "vite dev --port 3000",
"build": "vite build",
"start": "node .output/server/index.mjs"
}
The command is one program, installed by one line. Every command it has is in the CLI's reference.
curl -fsSL https://pethost.dev/install.sh | sh # macOS, Linux
irm https://pethost.dev/install.ps1 | iex # Windows, in PowerShell
The account needs a plan. If you are not signed in, pethost deploy opens your browser and signs you in. If you have no plan yet, it shows you where to choose one, and waits.
Deploy the TanStack Start app with one command
Go to the folder that has package.json and run pethost deploy. This is the whole screen, for the app the CLI created:
$ cd my-app
$ pethost deploy
Name it [my-app]: it will live at https://my-app.sam.pethost.app
✓ Packed 18 files, 183 KB (left out node_modules)
✓ Uploaded straight to your machine
✗ /compose.yaml: the project directory has no compose.yaml at its root: add one
✓ Node.js project detected, wrote Dockerfile.
✓ Packed 19 files, 184 KB (left out node_modules)
✓ Uploaded straight to your machine
✓ Built and started in 29 s
· wrote compose.yaml for the Dockerfile: the service app, reading .env
✓ app listens on 3000 → https://my-app.sam.pethost.app
It answers 200.
https://my-app.sam.pethost.app
Wrote .pethost (commit it). Next: pethost logs -f · pethost open
- It asks one thing The project's name, which is the first word of its address. Enter takes the folder's name.
- The machine finds nothing to run The folder goes straight to your machine, without
node_modules. The line with the cross is its answer: a project runs from a Dockerfile or a Compose file, and the folder has neither yet. - pethost writes the Dockerfile It read the
buildandstartscripts inpackage.json, and uploads the folder again. - The machine builds and starts it It sees that the server listens on 3000 and sends the address there. Then pethost asks the address itself, and prints what it answered: 200.
We asked the deployed app what a visitor asks. The home page and /about each answered 200 with server-rendered HTML, and an address with no route answered 404. The running server took 43 MB of memory.
The Dockerfile that pethost writes for TanStack Start
This is the file as it was written into the app's folder, whole:
# Written by pethost deploy for this Node.js project: Node 24 (no .nvmrc names another),
# npm installs it (package-lock.json), package.json builds it with "vite build",
# package.json starts it with "node .output/server/index.mjs".
# It is yours now: change it as you like. pethost does not write it again.
FROM node:24
WORKDIR /app
COPY . .
# Every dependency: what builds the project, and may start it, is among the ones for
# development.
RUN --mount=type=cache,target=/root/.npm \
npm install
RUN npm run build
ENV NODE_ENV=production
CMD ["npm", "run", "start"]
Its first lines say what pethost read in your folder. The package manager is the one your lockfile names, and the Node version is the one .nvmrc or .node-version names, or Node 24 where there is neither. The build and the start are your two scripts, as you wrote them.
Without the start script
A TanStack Start app can be built for several kinds of host, so pethost does not guess how yours starts. Without a start script it writes no file and says why:
$ pethost deploy
Name it [my-app]: it will live at https://my-app.sam.pethost.app
✓ Packed 13 files, 177 KB
✓ Uploaded straight to your machine
✗ /compose.yaml: the project directory has no compose.yaml at its root: add one
package.json builds the project and names nothing that starts it (no start script), and what it builds is no site of a kind pethost has a row for.
Your coding agent writes one in a minute: "Write a Dockerfile for this app".
Then run pethost deploy again. How Pethost runs a folder: https://pethost.dev/docs/api/#CreateProject
Add the script and run the command again.
Change a route and deploy again
Edit a route and run the same command. The second deploy took 7 seconds, because the machine keeps the build's layers and npm's cache:
$ pethost deploy
my-app (.pethost)
✓ Packed 20 files · uploaded · built and started in 7 s
· wrote compose.yaml for the Dockerfile: the service app, reading .env
· kept the project's x-pethost
It answers 200.
https://my-app.sam.pethost.app
When the build fails
We broke a route file to see it. The screen shows the build's log with the error in it, and the last line says what visitors get. This is that screen, shortened to three of its lines:
$ pethost deploy
my-app (.pethost)
✗ Deploy failed: failed to build: failed to solve: process "/bin/sh -c npm run build" did not complete successfully: exit code: 1
#9 0.793 Error: Error transforming route file /app/src/routes/about.tsx: SyntaxError: Unexpected token, expected "," (4:19)
Nothing changed: the version before still runs.
To deploy on every push, connect the repository once with pethost github sam/my-app. Pethost reads only the repositories you gave its GitHub App. pethost rollback puts the version before the current one back, and your machine keeps the three versions before it. An AI agent can do all of this for you through Pethost's MCP server: how an agent deploys and looks after a project.
Environment variables and your own domain
A variable that a server function reads is one command. It asks for the value without showing it, puts it into the project's .env file on the machine, and later deploys keep it:
pethost env set DATABASE_URL
Any name under your account's domain is an address at once, with HTTPS. A domain you own takes one command and one DNS record:
pethost domain add app.example.com
The command prints the record to make: a CNAME from your name to your machine's name. The certificate comes by itself once the name resolves, and renews itself.
What you get for the price
Pethost is €9.99 a month for everything you host, on 2 vCPU, 3 GB of memory and 30 GB of disk. The app's server took 43 MB of that memory, so the machine has room for its database, a worker and your other projects, such as a React Router app beside it. There is no fee per project and nothing metered: server functions are not billed by the call.
- €9.99 a month for the whole machine
- 29 s to build and start the app, the first time
- 7 s for the deploy after it
What is already done on it: HTTPS with certificates that renew themselves, deploys from GitHub, nightly backups kept for 14 days, SSH into any container, and every request counted, with the busiest paths and the error rate of the last 30 days. The machine is always on, so a server function never waits for a cold start. The plans are on the pricing part of the first page.
Pethost is the best pick for
- Developers with a full-stack React app: the server, its server functions and its database on one machine, on one bill
- Solo developers with several side projects, each at an address of its own
- People whose agent deploys for them: Claude Code or Codex puts the app online and reads its logs
- Early startups who want a fixed monthly cost while the product is small
Look elsewhere if
- Your application needs several regions or autoscaling
Questions
How do I run TanStack Start on a Node server?
Add the Nitro plugin to vite.config.ts and the script "start": "node .output/server/index.mjs" to package.json, as TanStack's hosting guide says. npm run build then writes the server into .output, and npm run start runs it on port 3000.
Does a TanStack Start app need a Dockerfile to deploy?
On Pethost a project runs from a Dockerfile or a Compose file, and you do not have to write it: once package.json has a build and a start script, pethost deploy writes the Dockerfile and deploys it. The file stays in your folder, and you can change it.
What happens when a TanStack Start build fails on deploy?
Nothing changes for visitors. The deploy stops, the screen shows the build's log with the error, and the version that ran before keeps running.
Can I deploy a TanStack Start app from GitHub on every push?
Yes. Deploy the folder once with pethost deploy, then run pethost github owner/repository. From then on every push to the repository deploys itself, and pethost rollback goes back to an earlier commit.
What does it cost to host a TanStack Start app on Pethost?
€9.99 a month for the Starter machine of 2 vCPU, 3 GB and 30 GB, with no fee per project and no charge per request: the same machine runs your other apps, sites and databases. There is no free tier. Prices are without VAT.
The screens are deploys of the app that npx @tanstack/cli@latest create --deployment nitro writes, with TanStack Start 1.168.61, Nitro 3.0.260610-beta and pethost 0.2.1, on a test machine of ours that had built nothing before. The account in them is the example one, sam.
Put your projects online today
A machine of your own, as many projects as fit, one flat price. Nothing metered, nothing billed on top.