Skip to content

Commit 7a05d57

Browse files
Update tanstack.mdx
1 parent f49a15e commit 7a05d57

File tree

1 file changed

+117
-67
lines changed
  • src/content/docs/workers/framework-guides/web-apps

1 file changed

+117
-67
lines changed

src/content/docs/workers/framework-guides/web-apps/tanstack.mdx

Lines changed: 117 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ sidebar:
55
order: 7
66
head: []
77
tags: ["full-stack"]
8-
description: Create a TanStack Router application and deploy it to Cloudflare Workers with Workers Assets.
8+
description: Create a TanStack Start application and deploy it to Cloudflare Workers with Workers Assets.
99
---
1010

1111
import { WranglerConfig, Steps, PackageManagers, Details } from "~/components";
1212

1313
## What is TanStack Start?
1414

15-
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 tools like Nitro and Vite.
15+
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.
1616

1717
## Create a new TanStack Start
1818

19-
TanStack provides a start-basic project. We'll use this starter project to create a new TanStack Start application.
19+
TanStack Start Beta has significantly improved Cloudflare compatibility compared to the Alpha version, making deployment and development much more straightforward.
2020

2121
<Steps>
2222

@@ -27,10 +27,10 @@ TanStack provides a start-basic project. We'll use this starter project to creat
2727
cd start-basic
2828
npm install
2929
```
30-
31-
<Details header="How is this project set up?">
32-
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](https://tanstack.com/start/latest/docs/framework/react/quick-start#examples) that you can use by replacing `start-basic` with the example you want to use.
33-
</Details>
30+
31+
<Details header="How is this project set up?">
32+
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](https://tanstack.com/start/latest/docs/framework/react/quick-start#examples) that you can use by replacing `start-basic` with the example you want to use.
33+
</Details>
3434

3535
2. **Develop locally**
3636

@@ -46,34 +46,33 @@ Whether you created a new TanStack Start project or are using an existing projec
4646

4747
<Steps>
4848

49-
1. **Install `unenv` & `nitroCloudflareBindings` package**
50-
51-
[`unenv`](https://github.com/unjs/unenv) is a package that normalizes runtime environments across Node.js, browsers, and edge runtimes like Cloudflare Workers. It’s essential for TanStack Router because certain Node.js APIs are unavailable in the Workers environment. `unenv` offers compatible replacements for those APIs.
52-
53-
[`nitro-cloudflare-dev`](https://github.com/nitrojs/nitro-cloudflare-dev) enables access to the Cloudflare runtime bindings like R2, D1, and other Cloudflare services in the development server.
54-
55-
<PackageManagers pkg="unenv nitro-cloudflare-dev" />
49+
1. **Configure Vite for Cloudflare compatibility**
5650

57-
2. **Modify the `app.config.ts` file**
58-
59-
To configure your application for Cloudflare Workers deployment, add the following lines to your `app.config.ts` file:
51+
Update your `vite.config.ts` file to use the `cloudflare-module` target for a compatible build:
6052

6153
```ts
62-
// Required imports
63-
import { cloudflare } from 'unenv'
64-
import nitroCloudflareBindings from "nitro-cloudflare-dev";
65-
66-
// Add this new server section to the defineConfig object
67-
server: {
68-
preset: "cloudflare-module",
69-
unenv: cloudflare,
70-
modules: [nitroCloudflareBindings],
71-
},
54+
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
55+
import { defineConfig } from "vite";
56+
import tsConfigPaths from "vite-tsconfig-paths";
57+
58+
export default defineConfig({
59+
server: {
60+
port: 3000,
61+
},
62+
plugins: [
63+
tsConfigPaths({
64+
projects: ["./tsconfig.json"],
65+
}),
66+
tanstackStart({
67+
target: "cloudflare-module", // Key configuration for Cloudflare compatibility
68+
}),
69+
],
70+
});
7271
```
7372

74-
This will set the correct build format and runtime environment for Cloudflare.
73+
This single configuration change is all that's needed to make your TanStack Start application compatible with Cloudflare Workers.
7574

76-
3. **Add a Wrangler file**
75+
2. **Add a Wrangler file**
7776

7877
Create a `wrangler.jsonc` or `wrangler.toml` file in the root of your project, `wrangler.jsonc` is the recommended approach. This file is used to configure the Cloudflare Workers deployment.
7978

@@ -82,23 +81,45 @@ Whether you created a new TanStack Start project or are using an existing projec
8281
```json
8382
{
8483
"$schema": "node_modules/wrangler/config-schema.json",
85-
"name": "start-basic",
86-
"main": "./.output/server/index.mjs",
87-
"compatibility_date": "2025-04-14",
84+
"name": "my-start-app",
85+
"main": ".output/server/index.mjs",
86+
"compatibility_date": "2025-04-10",
87+
"compatibility_flags": ["nodejs_compat"],
88+
"assets": {
89+
"directory": ".output/public"
90+
},
8891
"observability": {
8992
"enabled": true
9093
},
91-
"assets": {
92-
"directory": "./.output/public/"
93-
},
94-
"compatibility_flags": ["nodejs_compat"]
94+
"kv_namespaces": [
95+
{
96+
"binding": "CACHE",
97+
"id": "<Your KV ID>"
98+
}
99+
]
95100
}
96101
```
97102

98103
</WranglerConfig>
99104

100-
Note that the `directory` key is set to `.output/public/`, which is the folder that will be filled with the build output. Additionally, the `main` key is set to `.output/server/index.mjs`, indicating to Cloudflare Workers where to locate the entry point for your application.
105+
Note that the `directory` key is set to `.output/public`, which is the folder that will be filled with the build output. Additionally, the `main` key is set to `.output/server/index.mjs`, indicating to Cloudflare Workers where to locate the entry point for your application. The `kv_namespaces` section shows an example of how to configure a KV namespace binding.
106+
107+
3. **Add deployment scripts to package.json**
108+
109+
Add the following scripts to your `package.json` file to streamline deployment and type generation:
101110

111+
```json
112+
{
113+
"scripts": {
114+
...
115+
"deploy": "npm run build && wrangler deploy",
116+
"cf-typegen": "wrangler types --env-interface Env"
117+
}
118+
}
119+
```
120+
121+
The `deploy` script combines building and deploying in one command, while `cf-typegen` generates TypeScript types for your Cloudflare bindings.
122+
102123
4. **Build the application**
103124

104125
You must build your application before deploying it to Cloudflare Workers.
@@ -107,75 +128,104 @@ Whether you created a new TanStack Start project or are using an existing projec
107128

108129
5. **Deploy the application**
109130

110-
The command below will deploy your application to Cloudflare Workers and provide a deployment URL. Make sure to rebuild your application after making any changes to see those changes reflected in the deployment.
131+
You can now use the deploy script to build and deploy your application in one command:
132+
133+
<PackageManagers type="run" args={"deploy"} />
134+
135+
Alternatively, you can still deploy directly with Wrangler:
111136

112137
```sh
113138
npx wrangler deploy
114139
```
115140

116-
When making changes in the future ensure you rebuild your application. The deploy will deploy what is in your `.output/public` folder and that only gets updated when you run the build command.
117-
118141
</Steps>
119142

120143
## Using Cloudflare Bindings
121144

122145
<Steps>
123146

124-
1. **Create a helper function to get access to Cloudflare bindings**
147+
1. **Generate TypeScript types for your bindings**
148+
149+
Before using Cloudflare bindings in your code, generate the TypeScript types to ensure proper type safety:
150+
151+
<PackageManagers type="run" args={"cf-typegen"} />
125152

126-
Create a helper function named `cloudflareBindings.ts` in the `src/utils` folder, and paste in the below code. You can create a `utils` folder in your project if you don't already have one. The example assumes you have a KV namespace with a binding name of `CACHE` already created in your account and added to the wrangler file.
153+
This command reads your `wrangler.jsonc` configuration and generates an `Env` interface with all your configured bindings.
154+
155+
2. **Create a helper function to get access to Cloudflare bindings**
156+
157+
Create a helper function named `bindings.ts` in the `src/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 of `CACHE` already created in your account and added to the wrangler file.
158+
127159

128160
```ts
129-
import type { KVNamespace } from "@cloudflare/workers-types";
130161

131-
interface CloudflareBindings {
132-
CACHE: KVNamespace;
162+
let cachedEnv: Env | null = null;
163+
164+
// This gets called once at startup when running locally
165+
const initDevEnv = async () => {
166+
const { getPlatformProxy } = await import("wrangler");
167+
const proxy = await getPlatformProxy();
168+
cachedEnv = proxy.env as unknown as Env;
169+
};
170+
171+
if (import.meta.env.DEV) {
172+
await initDevEnv();
133173
}
174+
134175
/**
135176
* Will only work when being accessed on the server. Obviously, CF bindings are not available in the browser.
136177
* @returns
137178
*/
138-
export async function getBindings() {
179+
export function getBindings(): Env {
139180
if (import.meta.env.DEV) {
140-
const { getPlatformProxy } = await import("wrangler");
141-
const { env } = await getPlatformProxy();
142-
return env as unknown as CloudflareBindings;
181+
if (!cachedEnv) {
182+
throw new Error(
183+
"Dev bindings not initialized yet. Call initDevEnv() first."
184+
);
185+
}
186+
return cachedEnv;
143187
}
144188

145-
return process.env as unknown as CloudflareBindings;
189+
return process.env as unknown as Env;
146190
}
147191
```
148192

149193
<Details header="How is this code working?">
150-
To ensure your bindings work locally with vinxi, the helper function uses
151-
[getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy)
152-
method from wrangler. This logic is placed under a check if
153-
import.meta.env.DEV is true.
194+
The helper function uses [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#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 run `npm run cf-typegen` to generate the `Env` types that this code references.
154195
</Details>
155196

156-
2. **Example using a Cloudflare Binding**
197+
3. **Example using a Cloudflare Binding in Server Functions**
157198

158-
Now that you have a helper function to get access to your Cloudflare bindings, you can use them in your application.
199+
Now that you have a helper function to get access to your Cloudflare bindings, you can use them in your server functions.
159200

160201
Remember bindings are only available on the server.
161202

162203
```ts
163-
const bindings = await getBindings();
164-
const cache = bindings.CACHE;
165-
const queryCount = (await cache.get("queryCount")) || "0";
166-
await cache.put("queryCount", String(Number(queryCount) + 1));
204+
import { createServerFn } from "@tanstack/react-start";
205+
import { getBindings } from "~/utils/bindings";
206+
207+
const personServerFn = createServerFn({ method: "GET" })
208+
.validator((d: string) => d)
209+
.handler(async ({ data: name }) => {
210+
const env = getBindings();
211+
let growingAge = Number((await env.CACHE.get("age")) || 0);
212+
growingAge++;
213+
await env.CACHE.put("age", growingAge.toString());
214+
return { name, randomNumber: growingAge };
215+
});
167216
```
168217

169-
A special thanks to GitHub user [backpine](https://github.com/backpine) for the code that supports Cloudflare Bindings in TanStack, which is demonstrated in their [TanStack Start on Workers example](https://github.com/backpine/tanstack-start-on-cloudflare-workers-v0).
218+
A special thanks to GitHub user [backpine](https://github.com/backpine) for the code that supports Cloudflare Bindings in TanStack Start, which is demonstrated in their [TanStack Start Beta on Cloudflare example](https://github.com/backpine/tanstack-start-beta-on-cloudflare).
170219

171220
</Steps>
172221

173-
#### Optional: Update utils file with deployment URL
222+
## Environment Handling
223+
224+
The TanStack Start Beta version provides seamless environment handling:
174225

175-
This step is required for the `/users` page to function properly in the `start-basic` example. Update the `/src/utils/users.tsx` file with the Cloudflare Workers deployment URL.
226+
- **Development**: Bindings are accessed via `getPlatformProxy()` from Wrangler and cached at startup
227+
- **Production**: Bindings are accessed via `process.env`
176228

177-
```ts
178-
export const DEPLOY_URL = "YOUR_DEPLOYMENT_URL";
179-
```
229+
This approach ensures your bindings are properly typed throughout your project and provides a smooth development experience.
180230

181-
By following the steps above, you will have deployed your TanStack Start application to Cloudflare Workers.
231+
By following the steps above, you will have deployed your TanStack Start application to Cloudflare Workers. The Beta version has significantly improved Cloudflare compatibility compared to the Alpha version, making deployment and development much more straightforward.

0 commit comments

Comments
 (0)