Ploy
Ploy

TanStack Start

Run TanStack Start apps on Ploy with the ploy() Vite plugin — server routes, prerendering, and ploy.yaml config.

TanStack Start

TanStack Start apps run on Ploy through the same ploy() plugin used for other Vite apps. You get TanStack's file-based routing, server routes, and build-time prerendering, served on the Ploy Workers runtime — with bindings and configuration driven entirely from ploy.yaml.

TanStack Start requires the latest Vite. Pin vite to the current major (Vite 8+) in your project; older majors are not supported by the TanStack Start adapter.

Project setup

A TanStack Start project needs three pieces: a package.json that calls Ploy, a vite.config.ts that combines ploy() with the TanStack Start plugin, and a ploy.yaml.

package.json
{
	"scripts": {
		"build": "ploy vite build && tsc --noEmit",
		"types": "ploy types -o env.d.ts"
	},
	"dependencies": {
		"@tanstack/react-router": "^1.168.0",
		"@tanstack/react-start": "^1.167.0",
		"react": "^19",
		"react-dom": "^19"
	},
	"devDependencies": {
		"@meetploy/cli": "latest",
		"@meetploy/vite": "latest",
		"@vitejs/plugin-react": "^6",
		"vite": "^8"
	}
}
vite.config.ts
import { ploy } from "@meetploy/vite";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import viteReact from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
	plugins: [
		...ploy({ viteEnvironment: { name: "ssr" } }),
		tanstackStart({
			prerender: {
				enabled: true,
				autoSubfolderIndex: true,
				crawlLinks: false,
				failOnError: true,
			},
		}),
		viteReact(),
	],
});
ploy.yaml
kind: dynamic
build: pnpm build
out: dist
compatibility_date: "2026-03-17"
compatibility_flags:
  - nodejs_compat

ploy() returns an array of plugins, so spread it into the plugins list. Any plugin options you would pass to the underlying Vite integration (such as viteEnvironment) go directly to ploy().

When @tanstack/react-start is installed, Ploy automatically maps the worker entry to @tanstack/react-start/server-entry — there is no worker/index.ts to maintain.

Routing

TanStack Start uses file-based routing under src/routes. Pages render with React; server routes run on the worker.

src/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
	component: HomePage,
});

function HomePage() {
	return <h1>Rendered at build time, served from the worker</h1>;
}

Server routes

Add a server block to a route to handle requests on the worker — this is where API endpoints live.

src/routes/api/hello.ts
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/api/hello")({
	server: {
		handlers: {
			GET: ({ pathname }) =>
				Response.json({ message: "hello from worker", pathname }),
		},
	},
});

Prerendering

The TanStack Start plugin can prerender routes to static HTML at build time while keeping the app on the worker runtime for everything else. Configure it through the prerender option in vite.config.ts:

tanstackStart({
	prerender: {
		enabled: true,
		autoSubfolderIndex: true,
		crawlLinks: false,
		failOnError: true,
	},
});

Prerendered routes are emitted as static files and served as assets; dynamic routes and server handlers continue to run on the worker.

Bindings

Add Ploy resources — databases, queues, auth, and more — to ploy.yaml exactly as you would for any other Vite app. ploy() injects them into the worker so they are available on env in your server routes, backed by the local Ploy dev environment during ploy dev. See the Vite guide for the binding maps and Features for each resource.

ploy.yaml
db:
  DB: default

After changing bindings, regenerate types so env.d.ts stays current:

ploy types -o env.d.ts

Running it

# Dev server + local Ploy dashboard
ploy dev

# Production build
ploy vite build

ploy dev auto-detects the TanStack Start project and starts the Vite dev server alongside the local Ploy dashboard. See ploy dev and ploy vite for the command reference.

Example

A complete, runnable project — prerendered routes, a server route, and worker APIs — lives in examples/tanstack-start.

How is this guide?

Last updated on