TanStack Start
Last updated Oct 13, 2026 is a full-stack framework for building web applications with server-side rendering, streaming, server functions, and bundling.
Already have a TanStack Start project?
Run wrangler deploy in a project without a Wrangler configuration file and Wrangler will automatically detect TanStack Start, generate the necessary configuration, and deploy your project.
npmyarnpnpm
npx wrangler deploy
yarn wrangler deploy
pnpm wrangler deploy
For more information, refer to Automatic project configuration.
TanStack StartDetected
Generated configuration
wrangler.jsonc
main:@tanstack/react-start/server-entry
wrangler.jsonc
compatibility_flags:nodejs_compat
wrangler.jsonc
observability:enabled: true
WorkersDeployed
Wrangler handles configuration automatically
Create a new application
Create a TanStack Start application pre-configured for Cloudflare Workers:
npmyarnpnpm
npm create cloudflare@latest -- my-tanstack-start-app --framework=tanstack-start
yarn create cloudflare my-tanstack-start-app --framework=tanstack-start
pnpm create cloudflare@latest my-tanstack-start-app --framework=tanstack-start
Start a local development server to preview your project during development:
npmyarnpnpm
npm run dev
yarn run dev
pnpm run dev
Configure an existing application
If you have an existing TanStack Start application, configure it to run on Cloudflare Workers:
Note
Cloudflare does not support TanStack Start projects that use Rsbuild. If your application uses Rsbuild, migrate it to Vite before following these configuration steps.
- Install
@cloudflare/vite-pluginandwrangler:npmyarnpnpmbun
npm i -D @cloudflare/vite-plugin wrangler
yarn add -D @cloudflare/vite-plugin wrangler
pnpm add -D @cloudflare/vite-plugin wrangler
bun add -d @cloudflare/vite-plugin wrangler
- Add the Cloudflare plugin to your Vite configuration:
If your Vite configuration includes another deployment adapter, such as nitro(), remove the adapter and its import before adding the Cloudflare Vite plugin.
vite.config.jsjs
```js import { defineConfig } from "vite"; import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import { cloudflare } from "@cloudflare/vite-plugin"; import react from "@vitejs/plugin-react";
export default defineConfig({ plugins: [ cloudflare({ viteEnvironment: { name: "ssr" } }), tanstackStart(), react(), ], }); ```
vite.config.tsts
```ts import { defineConfig } from "vite"; import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import { cloudflare } from "@cloudflare/vite-plugin"; import react from "@vitejs/plugin-react";
export default defineConfig({ plugins: [ cloudflare({ viteEnvironment: { name: "ssr" } }), tanstackStart(), react(), ], }); ```
- Add a
wrangler.jsoncconfiguration file:
jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "<YOUR_PROJECT_NAME>",
// Set this to today's date
"compatibility_date": "2026-10-27",
"compatibility_flags": ["nodejs_compat"],
"main": "@tanstack/react-start/server-entry",
"observability": {
"enabled": true,
},
}
```toml
"$schema" = "node_modules/wrangler/config-schema.json"
name = "
[observability] enabled = true ```
- Update the
scriptssection inpackage.json:
package.jsonjson
json
{
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"deploy": "npm run build && wrangler deploy",
"cf-typegen": "wrangler types"
}
}
Deploy
Deploy to a *.workers.dev subdomain or a custom domain from your machine or any CI/CD system, including Workers Builds.
npmyarnpnpm
npm run deploy
yarn run deploy
pnpm run deploy
Note
Preview the build locally before deploying:
npmyarnpnpm
npm run preview
yarn run preview
pnpm run preview
Custom entrypoints
TanStack Start uses @tanstack/react-start/server-entry as your default entrypoint. Create a custom server entrypoint to add additional Workers handlers such as Queues and Cron Triggers. This is also where you can add additional exports such as Durable Objects and Workflows.
Note
If you are using TypeScript, generate Workers types before adding a custom entrypoint:
npmyarnpnpm
npm run cf-typegen
yarn run cf-typegen
pnpm run cf-typegen
- Create a custom server entrypoint file:
src/server.jsjs
```js import handler from "@tanstack/react-start/server-entry";
// Export Durable Objects as named exports export { MyDurableObject } from "./my-durable-object";
export default { fetch: handler.fetch,
// Handle Queue messages
async queue(batch, _env, _ctx) {
for (const message of batch.messages) {
console.log("Processing message:", message.body);
message.ack();
}
},
// Handle Cron Triggers
async scheduled(event, _env, _ctx) {
console.log("Cron triggered:", event.cron);
},
}; ```
src/server.tsts
```ts import handler from "@tanstack/react-start/server-entry";
// Export Durable Objects as named exports export { MyDurableObject } from "./my-durable-object";
export default { fetch: handler.fetch,
// Handle Queue messages
async queue(batch, _env, _ctx) {
for (const message of batch.messages) {
console.log("Processing message:", message.body);
message.ack();
}
},
// Handle Cron Triggers
async scheduled(event, _env, _ctx) {
console.log("Cron triggered:", event.cron);
},
} satisfies ExportedHandler
- Update your Wrangler configuration to point to your custom entrypoint:
jsonc
{
"main": "src/server.ts",
"upload_source_maps": true,
}
toml
main = "src/server.ts"
upload_source_maps = true
Test scheduled handlers locally
Test your scheduled handler locally using the /cdn-cgi/local/scheduled endpoint:
curl "http://localhost:3000/cdn-cgi/local/scheduled?cron=*+*+*+*+*"
<details>
<summary>
Example: Using Workflows
</summary>
Export a Workflow class from your custom entrypoint to run durable, multi-step tasks:
src/server.jsjs
import { WorkflowEntrypoint, WorkflowStep } from "cloudflare:workers";
export class MyWorkflow extends WorkflowEntrypoint {
async run(event, step) {
const result = await step.do("process data", async () => {
return `Processed: ${event.payload.input}`;
});
await step.sleep("wait", "10 seconds");
await step.do("finalize", async () => {
console.log("Workflow complete:", result);
});
}
}
src/server.tsts
import { WorkflowEntrypoint, WorkflowStep } from "cloudflare:workers";
import type { WorkflowEvent } from "cloudflare:workers";
export class MyWorkflow extends WorkflowEntrypoint<Env> {
async run(event: WorkflowEvent<{ input: string }>, step: WorkflowStep) {
const result = await step.do("process data", async () => {
return `Processed: ${event.payload.input}`;
});
await step.sleep("wait", "10 seconds");
await step.do("finalize", async () => {
console.log("Workflow complete:", result);
});
}
}
Add the Workflow configuration to your Wrangler configuration:
{
"workflows": [
{
"name": "my-workflow",
"binding": "MY_WORKFLOW",
"class_name": "MyWorkflow",
},
],
}
[[workflows]]
name = "my-workflow"
binding = "MY_WORKFLOW"
class_name = "MyWorkflow"
</details>
<details>
<summary>
Example: Using Service Bindings
</summary>
Add a service binding to call another Worker's RPC methods from your TanStack Start application:
{
"services": [
{
"binding": "AUTH_SERVICE",
"service": "auth-worker",
},
],
}
[[services]]
binding = "AUTH_SERVICE"
service = "auth-worker"
The target Worker must expose RPC methods by extending <a href="https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/rpc/"><code>WorkerEntrypoint</code></a>. Generate types for both Workers by passing both Wrangler configuration files:
npmyarnpnpm
npx wrangler types -c ./wrangler.jsonc -c ../auth-worker/wrangler.jsonc
yarn wrangler types -c ./wrangler.jsonc -c ../auth-worker/wrangler.jsonc
pnpm wrangler types -c ./wrangler.jsonc -c ../auth-worker/wrangler.jsonc
Call the bound Worker's methods from a server function:
src/routes/index.jsxjs
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";
const verifyUser = createServerFn()
.validator((token) => token)
.handler(async ({ data: token }) => {
const result = await env.AUTH_SERVICE.verify(token);
return result;
});
src/routes/index.tsxts
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";
const verifyUser = createServerFn()
.validator((token: string) => token)
.handler(async ({ data: token }) => {
const result = await env.AUTH_SERVICE.verify(token);
return result;
});
</details>
Bindings
Your TanStack Start application can be fully integrated with the Cloudflare Developer Platform, in both local development and in production, by using bindings.
Access bindings by importing the env object in your server-side code:
src/routes/index.jsxjs
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";
export const Route = createFileRoute("/")({
loader: () => getData(),
component: RouteComponent,
});
const getData = createServerFn().handler(() => {
// Access bindings via env
// For example: env.MY_KV, env.MY_BUCKET, or env.AI
});
function RouteComponent() {
// ...
}
src/routes/index.tsxts
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";
export const Route = createFileRoute("/")({
loader: () => getData(),
component: RouteComponent,
});
const getData = createServerFn().handler(() => {
// Access bindings via env
// For example: env.MY_KV, env.MY_BUCKET, or env.AI
});
function RouteComponent() {
// ...
}
Generate TypeScript types for your bindings based on your Wrangler configuration:
npmyarnpnpm
npm run cf-typegen
yarn run cf-typegen
pnpm run cf-typegen
With bindings, your application can be fully integrated with the Cloudflare Developer Platform, giving you access to compute, storage, AI and more.
Bindings
Access to compute, storage, AI and more.
Use R2 in a server function
Add an R2 bucket binding to your Wrangler configuration:
{
"r2_buckets": [
{
"binding": "MY_BUCKET",
"bucket_name": "<YOUR_BUCKET_NAME>",
},
],
}
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "<YOUR_BUCKET_NAME>"
Access the bucket in a server function:
src/routes/index.jsjs
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";
const uploadFile = createServerFn({ method: "POST" })
.validator((data) => data)
.handler(async ({ data }) => {
await env.MY_BUCKET.put(data.key, data.content);
return { success: true };
});
const getFile = createServerFn()
.validator((key) => key)
.handler(async ({ data: key }) => {
const object = await env.MY_BUCKET.get(key);
return object ? await object.text() : null;
});
src/routes/index.tsts
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";
const uploadFile = createServerFn({ method: "POST" })
.validator((data: { key: string; content: string }) => data)
.handler(async ({ data }) => {
await env.MY_BUCKET.put(data.key, data.content);
return { success: true };
});
const getFile = createServerFn()
.validator((key: string) => key)
.handler(async ({ data: key }) => {
const object = await env.MY_BUCKET.get(key);
return object ? await object.text() : null;
});
Static prerendering
Prerender your application to static HTML at build time and serve as static assets.
vite.config.jsjs
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
cloudflare({ viteEnvironment: { name: "ssr" } }),
tanstackStart({
prerender: {
enabled: true,
},
}),
react(),
],
});
vite.config.tsts
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
cloudflare({ viteEnvironment: { name: "ssr" } }),
tanstackStart({
prerender: {
enabled: true,
},
}),
react(),
],
});
For more options, refer to TanStack Start static prerendering ↗︎.
Prerendering data sources
Caution
Prerendering runs at build time. It uses your local environment variables, secrets, and bindings storage data.
To prerender with production data, use remote bindings.
In CI environments, environment variables or secrets may not be available during the build. To make them accessible:
- Set
CLOUDFLARE_INCLUDE_PROCESS_ENV=truein your CI environment and provide the required values as environment variables. - If using Workers Builds, update your build settings.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/framework-guides/web-apps/tanstack-start/#page","headline":"TanStack Start","description":"Deploy a TanStack Start application to Cloudflare Workers.","url":"https://developers.cloudflare.com/workers/framework-guides/web-apps/tanstack-start/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/framework-guides/web-apps/tanstack-start/og.png?v=7e028d16354c90aa","dateModified":"2026-10-13","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["full-stack"]}
description: Create a Vike application and deploy it to Cloudflare Workers title: Vike image: https://developers.cloudflare.com/workers/framework-guides/web-apps/vike/og.png?v=03ff0b22303f0ff3
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt
Use this file to discover all available pages before exploring further.
Docs