Deploy to Vercel as a TanStack Start app via Nitro

Vercel served 404s: with Hydrogen gone it treated the app as a static
Vite site, but TanStack Start's build has no index.html; pages come from
its server. Add the hosting adapter TanStack documents for Vercel:

- nitro() in vite.config, for 'vite build' only (dev and the nodesandbox
  runtime never load it); on Vercel it writes .vercel/output with the
  static assets and one Node.js function running Start + Hono
- vercel.json: tanstack-start preset, Yarn 4 via Corepack
- 'yarn start' runs the Node build; canonical URLs use the Vercel domain

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Rami Bitar
2026-10-03 15:47:53 -04:00
co-authored by Claude Opus 5.5
parent 7ec0029b08
commit 55423c7204
6 changed files with 182 additions and 7 deletions
+3
View File
@@ -1,6 +1,9 @@
.DS_Store
node_modules/*
dist
.output
.nitro
.vercel
.yarn/install-state.gz
.env*.local
src/routeTree.gen.ts
+12 -2
View File
@@ -20,9 +20,19 @@ yarn dev # http://localhost:3000
| Script | What it does |
| ---------------- | --------------------------------------------------------- |
| `yarn dev` | Vite dev server with SSR and the Hono `/api` routes |
| `yarn build` | Production build to `dist/` |
| `yarn build` | Production build; Nitro packages the server for the host |
| `yarn start` | Run the Node build from `.output/` |
| `yarn typecheck` | `tsc` |
## Deploying to Vercel
Push and deploy — no dashboard settings. `vercel.json` selects the TanStack
Start preset and installs with Yarn 4 via Corepack. During `vite build` the
Nitro plugin detects Vercel and writes `.vercel/output/` (static assets plus one
Node.js function running TanStack Start, with Hono serving `/api/*`). Set
`VITE_SHOPIFY_*` in the project to use a real store; without them it uses
mock.shop.
## nodesandbox compatibility
The sandbox runs Vite's native tools as WebAssembly (`NAPI_RS_FORCE_WASI`), and
@@ -37,7 +47,7 @@ its installer resolves from `package.json` ranges rather than `yarn.lock`. So:
optional dependency itself, and npm on other hosts rejects them
(`EBADPLATFORM`).
- `@vitejs/plugin-react` (6.0.0) and Tailwind (4.3.1) match the harness samples.
- No Nitro.
- Nitro (the hosting adapter) only loads for `vite build`, never in `vite dev`.
## Layout
+2
View File
@@ -6,6 +6,7 @@
"scripts": {
"dev": "vite dev --host 0.0.0.0 --port 3000",
"build": "vite build",
"start": "node .output/server/index.mjs",
"typecheck": "tsc --noEmit"
},
"packageManager": "yarn@4.18.0+sha512.fcb8716fe7cd0eece141ffc18b92193a9df9204c1ba83189c288835223fc0bbe64af473bab0d5e9927a7daeb5caf2bb07eb2787cc9338ca040ea125f2a1f2f7e",
@@ -24,6 +25,7 @@
"framer-motion": "^12.42.2",
"hono": "^4.13.12",
"lucide-react": "^0.562.0",
"nitro": "3.0.260903-beta",
"radix-ui": "^1.6.7",
"react": "^19.3.0",
"react-dom": "^19.3.0",
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "tanstack-start",
"installCommand": "corepack enable && yarn install",
"buildCommand": "yarn build"
}
+14 -4
View File
@@ -5,14 +5,24 @@ import tailwindcss from '@tailwindcss/vite';
import { fileURLToPath, URL } from 'node:url';
// Absolute origin for canonical and Open Graph URLs. Inlined at build time so
// the server render and the client agree on it; set VITE_SITE_URL in production.
const siteUrl = process.env.VITE_SITE_URL ?? 'http://localhost:3000';
// the server render and the client agree on it. On Vercel the production domain
// is used automatically; VITE_SITE_URL overrides it anywhere.
const siteUrl =
process.env.VITE_SITE_URL ??
(process.env.VERCEL_PROJECT_PRODUCTION_URL
? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
: 'http://localhost:3000');
export default defineConfig({
export default defineConfig(async ({ command }) => ({
server: { port: 3000 },
plugins: [
// Start must come before the React plugin.
tanstackStart(),
// Hosting adapter for `vite build`: Nitro packages Start's server for the
// host (a Vercel Function when building on Vercel, a Node server in
// .output/ elsewhere). Dev never loads it, so `vite dev` — and the
// nodesandbox runtime — run plain Vite + TanStack Start + Hono.
...(command === 'build' ? [(await import('nitro/vite')).nitro()] : []),
react(),
tailwindcss(),
],
@@ -24,4 +34,4 @@ export default defineConfig({
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
});
}));
+145 -1
View File
@@ -2465,6 +2465,13 @@ __metadata:
languageName: node
linkType: hard
"consola@npm:^3.4.2":
version: 3.4.2
resolution: "consola@npm:3.4.2"
checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a
languageName: node
linkType: hard
"convert-source-map@npm:^2.0.0":
version: 2.0.0
resolution: "convert-source-map@npm:2.0.0"
@@ -2479,6 +2486,18 @@ __metadata:
languageName: node
linkType: hard
"crossws@npm:^0.4.12":
version: 0.4.12
resolution: "crossws@npm:0.4.12"
peerDependencies:
srvx: ">=0.11.5"
peerDependenciesMeta:
srvx:
optional: true
checksum: 10c0/28d95429d666e2b925ccdc1c2f01ad23de21b7a8772cf063281127b9eea4a1b80c459f8404957d7231609750ff81ed6a6514e9c393a3130f35919e7a98a854ce
languageName: node
linkType: hard
"csstype@npm:^3.2.2":
version: 3.2.3
resolution: "csstype@npm:3.2.3"
@@ -2486,6 +2505,13 @@ __metadata:
languageName: node
linkType: hard
"db0@npm:^0.4.1":
version: 0.4.1
resolution: "db0@npm:0.4.1"
checksum: 10c0/2f965e59496455e2c8105f7f17bbbb8a93aefbe6d023cb6670ccba4757ee3ea99ae45be9b190ce87a98257d75a11fa98d1fbe506757360f7dc57adb9465c953e
languageName: node
linkType: hard
"debug@npm:^4.1.0, debug@npm:^4.3.1":
version: 4.4.3
resolution: "debug@npm:4.4.3"
@@ -2543,6 +2569,20 @@ __metadata:
languageName: node
linkType: hard
"env-runner@npm:^0.2.1":
version: 0.2.3
resolution: "env-runner@npm:0.2.3"
dependencies:
crossws: "npm:^0.4.12"
exsolve: "npm:^1.1.1"
httpxy: "npm:^0.5.5"
srvx: "npm:^1.0.5"
bin:
env-runner: ./dist/cli.mjs
checksum: 10c0/b72e0cf4dc17257b963c4dd265749bf68eea721558d82bcedb7b0684d946c8624b8c57949485f54bef86fea92a3fe5abce66cd1e3b70abcb8177950079fb5f0d
languageName: node
linkType: hard
"escalade@npm:^3.2.0":
version: 3.2.0
resolution: "escalade@npm:3.2.0"
@@ -2662,6 +2702,26 @@ __metadata:
languageName: node
linkType: hard
"h3@npm:^2.0.1-rc.31":
version: 2.0.1-rc.32
resolution: "h3@npm:2.0.1-rc.32"
dependencies:
rou3: "npm:^0.9.2"
srvx: "npm:^1.0.5"
peerDependencies:
crossws: ^0.4.12
ocache: ">=0.3.0"
peerDependenciesMeta:
crossws:
optional: true
ocache:
optional: true
bin:
h3: ./bin/h3.mjs
checksum: 10c0/182881ebf9c866f79ca120e8bc1b8a8850c34673758b67593fed7217cf04387294241e63397e20dd690c39cad05c6ce070eefc0707d7813ecfa9e358c66edd59
languageName: node
linkType: hard
"hono@npm:^4.13.12":
version: 4.13.12
resolution: "hono@npm:4.13.12"
@@ -2669,6 +2729,20 @@ __metadata:
languageName: node
linkType: hard
"hookable@npm:^6.1.1":
version: 6.1.2
resolution: "hookable@npm:6.1.2"
checksum: 10c0/ea5cdb1b1a1919b48cfbbfb55c8009f6843473ff50f67d6e959fd291cb2fd0a4934e85124bfd6531b1d2edf1e0675bc5954f85a12318a59b15c7a3e5667f0d4e
languageName: node
linkType: hard
"httpxy@npm:^0.5.5":
version: 0.5.5
resolution: "httpxy@npm:0.5.5"
checksum: 10c0/7be52cbfbd4157b4ac3aa22124d06081e8ffc50a185622e43c0ce8229bbcd7411d016f4a364fecb694325ed312823efbf51c70fa8049563a8b6b617642914cd3
languageName: node
linkType: hard
"isbot@npm:^5.1.22":
version: 5.2.2
resolution: "isbot@npm:5.2.2"
@@ -3043,6 +3117,36 @@ __metadata:
languageName: node
linkType: hard
"nf3@npm:^0.3.24":
version: 0.3.24
resolution: "nf3@npm:0.3.24"
checksum: 10c0/6c971b63634b6f7838194b5266fb40a8cb763d55a83b07a58ec3cf044fba1eef2fddfb6ee4d760ac3fbda34f69b9c04ddb923505cff3bbb57b7836c33c54b8ed
languageName: node
linkType: hard
"nitro@npm:3.0.260903-beta":
version: 3.0.260903-beta
resolution: "nitro@npm:3.0.260903-beta"
dependencies:
consola: "npm:^3.4.2"
crossws: "npm:^0.4.12"
db0: "npm:^0.4.1"
env-runner: "npm:^0.2.1"
h3: "npm:^2.0.1-rc.31"
hookable: "npm:^6.1.1"
nf3: "npm:^0.3.24"
ocache: "npm:^0.3.0"
rolldown: "npm:^1.2.7"
rou3: "npm:^0.9.2"
srvx: "npm:^1.0.3"
unenv: "npm:^2.0.0-rc.24"
unstorage: "npm:^2.0.0-alpha.10"
bin:
nitro: dist/cli/index.mjs
checksum: 10c0/7947c389578c42333b5e8e2bf21e275c5396cb6a9e25ca87ff80c108d199a5a2aa60e08aad369d67c853f866aa4eb355b5e3ca985f17df67dad90f5449a74754
languageName: node
linkType: hard
"node-gyp@npm:latest":
version: 13.1.0
resolution: "node-gyp@npm:13.1.0"
@@ -3081,6 +3185,13 @@ __metadata:
languageName: node
linkType: hard
"ocache@npm:^0.3.0":
version: 0.3.0
resolution: "ocache@npm:0.3.0"
checksum: 10c0/1caf0f8d24ef638dde0c4a5301376c7c1d0f44f4e7ed5430012c1983d0a1af6436b5243c3adf9c85ec0d4f33c1a2ab211351fe55337cd7308abe190557f37bbd
languageName: node
linkType: hard
"pathe@npm:^2.0.3":
version: 2.0.3
resolution: "pathe@npm:2.0.3"
@@ -3278,7 +3389,7 @@ __metadata:
languageName: node
linkType: hard
"rolldown@npm:~1.2.11":
"rolldown@npm:^1.2.7, rolldown@npm:~1.2.11":
version: 1.2.12
resolution: "rolldown@npm:1.2.12"
dependencies:
@@ -3343,6 +3454,13 @@ __metadata:
languageName: node
linkType: hard
"rou3@npm:^0.9.2":
version: 0.9.2
resolution: "rou3@npm:0.9.2"
checksum: 10c0/4b0ab14fbd3a7c60ffee1af644f618a9e76dd218cd4fbb585b8fa3601a3f25857c2b1656a215389379a7aef1e1e1897fd55e835658e9c3a5d9683571b36b3bd6
languageName: node
linkType: hard
"scheduler@npm:^0.28.0":
version: 0.28.0
resolution: "scheduler@npm:0.28.0"
@@ -3407,6 +3525,15 @@ __metadata:
languageName: node
linkType: hard
"srvx@npm:^1.0.3, srvx@npm:^1.0.5":
version: 1.0.5
resolution: "srvx@npm:1.0.5"
bin:
srvx: ./bin/srvx.mjs
checksum: 10c0/7ff87707840af95b399a11ab0b2fba6ded66a1d4658324913a1c95c916304056e5e618a9fc93803c1351aaf6acf4f7f3c5f55f18e82110a2ce876246d770c881
languageName: node
linkType: hard
"tailwind-merge@npm:^3.7.0":
version: 3.7.0
resolution: "tailwind-merge@npm:3.7.0"
@@ -3499,6 +3626,15 @@ __metadata:
languageName: node
linkType: hard
"unenv@npm:^2.0.0-rc.24":
version: 2.0.0-rc.24
resolution: "unenv@npm:2.0.0-rc.24"
dependencies:
pathe: "npm:^2.0.3"
checksum: 10c0/e8556b4287fcf647f23db790eea2782cc79f182370718680e3aba4753d5fb7177abf5d6df489c8f74f7e3ad6cd554b8623cc01caf3e6f2d5548e69178adb1691
languageName: node
linkType: hard
"unplugin@npm:^3.3.0":
version: 3.4.0
resolution: "unplugin@npm:3.4.0"
@@ -3542,6 +3678,13 @@ __metadata:
languageName: node
linkType: hard
"unstorage@npm:^2.0.0-alpha.10":
version: 2.0.0-alpha.10
resolution: "unstorage@npm:2.0.0-alpha.10"
checksum: 10c0/60473155ac6900020462f4d4192ff8a300cd510e8739f7b1905faece74fe0438b01cf00a84bcda81166cc3344838492e352998e1c48d8bc1449b1191d82ed3f7
languageName: node
linkType: hard
"update-browserslist-db@npm:^1.3.3":
version: 1.3.3
resolution: "update-browserslist-db@npm:1.3.3"
@@ -3619,6 +3762,7 @@ __metadata:
framer-motion: "npm:^12.42.2"
hono: "npm:^4.13.12"
lucide-react: "npm:^0.562.0"
nitro: "npm:3.0.260903-beta"
radix-ui: "npm:^1.6.7"
react: "npm:^19.3.0"
react-dom: "npm:^19.3.0"