Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/start/framework/react/guide/hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,32 @@ Deploy your application to Cloudflare Workers using their one-click deployment p

A full TanStack Start example for Cloudflare Workers is available [here](https://github.com/TanStack/router/tree/main/examples/react/start-basic-cloudflare).

#### Deployment fails even though the Vite build succeeds

If Wrangler reports a missing server entry or unresolved Start virtual modules, check whether your deployment command passes `--config wrangler.jsonc`. With the Cloudflare Vite plugin, that file is the build input. The plugin generates a deployment config with the built server entry and client assets, then writes `.wrangler/deploy/config.json` so Wrangler can find it. Forcing Wrangler to read the source config bypasses that redirect.

Run these commands from the application directory to validate the generated deployment without publishing:

```sh
pnpm run build
pnpm exec wrangler deploy --dry-run
```

Check that Wrangler reports the generated config under `dist`, rather than just the source `wrangler.jsonc`. Keep the source `main` set to `@tanstack/react-start/server-entry` or your custom server entry, and let the Vite plugin generate the deployment entry. Marking unresolved Start modules as external does not fix the missing build transformation.

If your build and deployment run in separate jobs, preserve the build output and `.wrangler/deploy/config.json` with their relative paths, or explicitly pass the generated deployment config. Do not edit generated files to repair the source configuration. See Cloudflare's [generated configuration documentation](https://developers.cloudflare.com/workers/wrangler/configuration/#generated-configuration) for how Wrangler finds that output.

For a named Cloudflare environment, select it when building. For example, if `env.staging` is defined in your source config:

```sh
CLOUDFLARE_ENV=staging pnpm run build
pnpm exec wrangler deploy --dry-run
```

The plugin resolves the environment into the generated config. A later `wrangler deploy --env staging` does not select a different built environment. See [Cloudflare environments](https://developers.cloudflare.com/workers/vite-plugin/reference/cloudflare-environments/).

The [Cloudflare fixture tests](https://github.com/TanStack/router/blob/main/e2e/react-start/basic-cloudflare/tests/app.spec.ts) exercise a generated-config dry run and preview the built app locally. A dry run validates packaging, it does not verify account permissions, a live domain, or deployed bindings.

### Netlify ⭐ _Official Partner_

<a href="https://www.netlify.com?utm_source=tanstack" alt="Netlify Logo">
Expand Down
18 changes: 18 additions & 0 deletions e2e/react-start/basic-cloudflare/tests/app.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { execFileSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import { existsSync } from 'node:fs'
import { join } from 'node:path'
import { expect } from '@playwright/test'
Expand Down Expand Up @@ -29,3 +31,19 @@ test('prerender with Cloudflare Workers runtime', async ({ page }) => {
'The value is Hello from Cloudflare',
)
})

test('the built Cloudflare app passes a deployment dry run', () => {
const wrangler = fileURLToPath(
new URL('../node_modules/wrangler/bin/wrangler.js', import.meta.url),
)
const output = execFileSync(
process.execPath,
[wrangler, 'deploy', '--dry-run'],
{
encoding: 'utf8',
env: { ...process.env, WRANGLER_SEND_METRICS: 'false' },
},
)
expect(output).toContain('dist/server/wrangler.json')
expect(output).toContain('--dry-run: exiting now.')
})
Loading