TanStack
TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more using Vite and modern web standards.
TanStack Start Beta has significantly improved Cloudflare compatibility compared to the Alpha version, making deployment and development much more straightforward.
-
Create a new TanStack Start project
Terminal window npx gitpick TanStack/router/tree/main/examples/react/start-basic start-basiccd start-basicnpm installHow is this project set up?
This command will clone the TanStack Start basic project to your local machine, change directory to the project, and install the dependencies. TanStack provides other examples ↗ that you can use by replacing
start-basic
with the example you want to use. -
Develop locally
After creating your project, run the following command in your project directory to start a local development server. By default this starts a local development server on
http://localhost:3000/
Terminal window npm run devTerminal window yarn run devTerminal window pnpm run dev
Whether you created a new TanStack Start project or are using an existing project, you'll need to make some changes to prepare for deployment to Cloudflare Workers.
-
Configure Vite for Cloudflare compatibility
Update your
vite.config.ts
file to use thecloudflare-module
target for a compatible build:vite.config.ts import { tanstackStart } from "@tanstack/react-start/plugin/vite";import { defineConfig } from "vite";import tsConfigPaths from "vite-tsconfig-paths";export default defineConfig({server: {port: 3000,},plugins: [tsConfigPaths({projects: ["./tsconfig.json"],}),tanstackStart({target: "cloudflare-module", // Key configuration for Cloudflare compatibility}),],});This single configuration change is all that's needed to make your TanStack Start application compatible with Cloudflare Workers.
-
Add a Wrangler file
Create a
wrangler.jsonc
orwrangler.toml
file in the root of your project,wrangler.jsonc
is the recommended approach. This file is used to configure the Cloudflare Workers deployment.{"$schema": "node_modules/wrangler/config-schema.json","name": "my-start-app","main": ".output/server/index.mjs","compatibility_date": "2025-06-25","compatibility_flags": ["nodejs_compat"],"assets": {"directory": ".output/public"},"observability": {"enabled": true},"kv_namespaces": [{"binding": "CACHE","id": "<Your KV ID>"}]}"$schema" = "node_modules/wrangler/config-schema.json"name = "my-start-app"main = ".output/server/index.mjs"compatibility_date = "2025-06-25"compatibility_flags = [ "nodejs_compat" ][assets]directory = ".output/public"[observability]enabled = true[[kv_namespaces]]binding = "CACHE"id = "<Your KV ID>"Note that the
directory
key is set to.output/public
, which is the folder that will be filled with the build output. Additionally, themain
key is set to.output/server/index.mjs
, indicating to Cloudflare Workers where to locate the entry point for your application. Thekv_namespaces
section shows an example of how to configure a KV namespace binding. -
Add deployment scripts to package.json
Add the following scripts to your
package.json
file to streamline deployment and type generation:"package.json {"scripts": {..."deploy": "npm run build && wrangler deploy","cf-typegen": "wrangler types --env-interface Env"}}The
deploy
script combines building and deploying in one command, whilecf-typegen
generates TypeScript types for your Cloudflare bindings. -
Build the application
You must build your application before deploying it to Cloudflare Workers.
Terminal window npm run buildTerminal window yarn run buildTerminal window pnpm run build -
Deploy the application
You can now use the deploy script to build and deploy your application in one command:
Terminal window npm run deployTerminal window yarn run deployTerminal window pnpm run deployAlternatively, you can still deploy directly with Wrangler:
Terminal window npx wrangler deploy
-
Generate TypeScript types for your bindings
Before using Cloudflare bindings in your code, generate the TypeScript types to ensure proper type safety:
Terminal window npm run cf-typegenTerminal window yarn run cf-typegenTerminal window pnpm run cf-typegenThis command reads your
wrangler.jsonc
configuration and generates anEnv
interface with all your configured bindings. -
Create a helper function to get access to Cloudflare bindings
Create a helper function named
bindings.ts
in thesrc/utils
folder (create the folder if it doesn't exist), and paste in the below code. The example assumes you have a KV namespace with a binding name ofCACHE
already created in your account and added to the wrangler file.src/utils/bindings.ts let cachedEnv: Env | null = null;// This gets called once at startup when running locallyconst initDevEnv = async () => {const { getPlatformProxy } = await import("wrangler");const proxy = await getPlatformProxy();cachedEnv = proxy.env as unknown as Env;};if (import.meta.env.DEV) {await initDevEnv();}/*** Will only work when being accessed on the server. Obviously, CF bindings are not available in the browser.* @returns*/export function getBindings(): Env {if (import.meta.env.DEV) {if (!cachedEnv) {throw new Error("Dev bindings not initialized yet. Call initDevEnv() first.");}return cachedEnv;}return process.env as unknown as Env;}How is this code working?
The helper function uses getPlatformProxy method from wrangler to provide access to your Cloudflare bindings during local development. The bindings are cached at startup for better performance. In production, bindings are accessed via
process.env
. Make sure you've runnpm run cf-typegen
to generate theEnv
types that this code references. -
Example using a Cloudflare Binding in Server Functions
Now that you have a helper function to get access to your Cloudflare bindings, you can use them in your server functions.
Remember bindings are only available on the server.
import { createServerFn } from "@tanstack/react-start";import { getBindings } from "~/utils/bindings";const personServerFn = createServerFn({ method: "GET" }).validator((d: string) => d).handler(async ({ data: name }) => {const env = getBindings();let growingAge = Number((await env.CACHE.get("age")) || 0);growingAge++;await env.CACHE.put("age", growingAge.toString());return { name, randomNumber: growingAge };});A special thanks to GitHub user backpine ↗ for the code that supports Cloudflare Bindings in TanStack Start, which is demonstrated in their TanStack Start Beta on Cloudflare example ↗.
The TanStack Start Beta version provides seamless environment handling:
- Development: Bindings are accessed via
getPlatformProxy()
from Wrangler and cached at startup - Production: Bindings are accessed via
process.env
This approach ensures your bindings are properly typed throughout your project and provides a smooth development experience.
By following the steps above, you will have deployed your TanStack Start application to Cloudflare Workers.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-