Skip to content
247 changes: 64 additions & 183 deletions src/content/docs/workers/framework-guides/web-apps/tanstack.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,224 +8,105 @@ tags: ["full-stack"]
description: Create a TanStack Start application and deploy it to Cloudflare Workers with Workers Assets.
---

import { WranglerConfig, Steps, PackageManagers, Details } from "~/components";
import {
Badge,
Description,
InlineBadge,
Render,
PackageManagers,
} from "~/components";

## What is TanStack Start?
In this guide, you will create a new [TanStack Start](https://tanstack.com/start) application and deploy it to Cloudflare Workers (with the new [Workers Assets](/workers/static-assets/)).

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.
## 1. Set up a new project

## Create a new TanStack Start
Start by cloning the Cloudflare example from the official TanStack repository.

TanStack Start Beta has significantly improved Cloudflare compatibility compared to the Alpha version, making deployment and development much more straightforward.
<PackageManagers
type="dlx"
pkg="gitpick"
args="TanStack/router/tree/main/examples/react/start-basic-cloudflare my-tanstack-app"
/>

<Steps>
After setting up your project, change your directory by running the following command:

1. **Create a new TanStack Start project**
```sh
cd my-tanstack-app
```

```sh
npx gitpick TanStack/router/tree/main/examples/react/start-basic start-basic
cd start-basic
npm install
```

<Details header="How 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](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.
</Details>
And install the project's dependencies with:

2. **Develop locally**
<PackageManagers type="install" />

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/`
## 2. Develop locally

<PackageManagers type="run" args="dev" />
After you have created your project, run the following command in the project directory to start a local development server. This will allow you to preview your project locally during development.

</Steps>
<PackageManagers type="run" args="dev" />

## Preparing for Deployment to Cloudflare Workers
## 3. Deploy your Project

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.
Your project can be deployed to a `*.workers.dev` subdomain or a [Custom Domain](/workers/configuration/routing/custom-domains/), from your own machine or from any CI/CD system, including [Cloudflare's own](/workers/ci-cd/builds/).

<Steps>
To deploy your application you will first need to build it:

1. **Configure Vite for Cloudflare compatibility**
<PackageManagers type="run" args="build" />

Update your `vite.config.ts` file to use the `cloudflare-module` target for a compatible build:
Once it's been built you can deploy it via:

```ts title="vite.config.ts" {14}
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { defineConfig } from "vite";
import tsConfigPaths from "vite-tsconfig-paths";
<PackageManagers type="run" args="deploy" />

export default defineConfig({
server: {
port: 3000,
},
plugins: [
tsConfigPaths({
projects: ["./tsconfig.json"],
}),
tanstackStart({
target: "cloudflare-module", // Key configuration for Cloudflare compatibility
}),
],
});
```
If you're using CI, ensure you update your ["deploy command"](/workers/ci-cd/builds/configuration/#build-settings) configuration appropriately.

This single configuration change is all that's needed to make your TanStack Start application compatible with Cloudflare Workers.
:::note

2. **Add a Wrangler file**
After having built the application you can run the `preview` script to preview the built output locally before deploying it.
This can help you making sure that your application will work as intended once it's been deployed to the Cloudflare network:

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.
<PackageManagers type="run" args="preview" />

<WranglerConfig>
:::

```json
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-start-app",
"main": ".output/server/index.mjs",
"compatibility_date": "$today",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": ".output/public"
},
"observability": {
"enabled": true
},
"kv_namespaces": [
{
"binding": "CACHE",
"id": "<Your KV ID>"
}
]
}
```

</WranglerConfig>

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.

3. **Add deployment scripts to package.json**

Add the following scripts to your `package.json` file to streamline deployment and type generation:

```json title="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, while `cf-typegen` generates TypeScript types for your Cloudflare bindings.

4. **Build the application**

You must build your application before deploying it to Cloudflare Workers.

<PackageManagers type="run" args={"build"} />

5. **Deploy the application**

You can now use the deploy script to build and deploy your application in one command:

<PackageManagers type="run" args={"deploy"} />

Alternatively, you can still deploy directly with Wrangler:

```sh
npx wrangler deploy
```

</Steps>

## Using Cloudflare Bindings

<Steps>

1. **Generate TypeScript types for your bindings**

Before using Cloudflare bindings in your code, generate the TypeScript types to ensure proper type safety:

<PackageManagers type="run" args={"cf-typegen"} />

This command reads your `wrangler.jsonc` configuration and generates an `Env` interface with all your configured bindings.

2. **Create a helper function to get access to Cloudflare bindings**

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.


```ts title="src/utils/bindings.ts"

let cachedEnv: Env | null = null;

// This gets called once at startup when running locally
const 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;
}
## Bindings

return process.env as unknown as Env;
}
```
Your TanStack Start application can be fully integrated with the Cloudflare Developer Platform, in both local development and in production, by using bindings.

<Details header="How is this code working?">
The helper function uses [getPlatformProxy](/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.
</Details>
You can use bindings simply by [importing the `env` object](https://developers.cloudflare.com/workers/runtime-apis/bindings/#importing-env-as-a-global) and accessing it in your server
side code.

3. **Example using a Cloudflare Binding in Server Functions**
For example in the following way:

Now that you have a helper function to get access to your Cloudflare bindings, you can use them in your server functions.
```tsx
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";
import { env } from "cloudflare:workers";

Remember bindings are only available on the server.
export const Route = createFileRoute("/")({
loader: () => getData(),
component: RouteComponent,
});

```ts
import { createServerFn } from "@tanstack/react-start";
import { getBindings } from "~/utils/bindings";
const getData = createServerFn().handler(() => {
// Use env here
});

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 };
});
```
function RouteComponent() {
// ...
}
```

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).
See `src/routes/index.tsx` for an example.

</Steps>
:::note

## Environment Handling
Running the `cf-typegen` script:

The TanStack Start Beta version provides seamless environment handling:
<PackageManagers type="run" args="cf-typegen" />

- **Development**: Bindings are accessed via [`getPlatformProxy()`](/workers/wrangler/api/#getplatformproxy) from Wrangler and cached at startup
- **Production**: Bindings are accessed via [`process.env`](/workers/runtime-apis/nodejs/process/#processenv)
Will populate the `env` object with the various bindings based on your configuration.

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.
<Render file="frameworks-bindings" product="workers" />
Loading