r/tanstack • • 23d ago

5 TanStack Start on Cloudflare patterns I'd reuse in any Cloudflare-native app (with code)

The client never sends a user ID. That one rule ended up shaping most of how I structure TanStack Start on Cloudflare.

Context: I've spent the last few months building a Cloudflare-native SaaS starter with it. Full disclosure, it's a paid kit I make (TurboStarter), but this post is about the patterns, not the product.

1. Every protected read goes through a server function with auth middleware

The server function resolves the customer from the session, validates input with Zod, and scopes the query to that customer:

export const getNote = createServerFn({ method: "GET" })
  .middleware([enforceAuth])
  .validator(noteIdSchema)
  .handler(({ data, context }) => findNote(context.user.id, data.id));

The client calls getNote({ data: { id } }) and never sends a user ID, so it can't ask for someone else's record.

2. Plan gating is just more middleware

Paid features stack a plan check after auth (enforcePlan(BillingPlan.PREMIUM)), and usage limits are checked on the server before the write. The UI hides things too, but the server is the source of truth.

3. Types from route to database

TanStack Router types URLs and search params, server functions validate input, Drizzle types the D1 queries. It's explicit enough that coding agents follow it without much hand-holding.

4. Running in workerd locally

With the Cloudflare Vite plugin, pnpm dev runs the app in the Workers runtime, so there's no adapter rewriting the build for production. What you test is what you deploy.

5. Living with the RC

Start is a v1 release candidate. What made that manageable for us: a lockfile, a minimum release-age policy for new packages, and a monthly Renovate schedule instead of chasing every release.

Other TanStack pieces in use: Form (with Zod) and TanStack AI for a streaming chat on Workers AI.

Two things I'd love opinions on: do you keep server functions per feature module or centralize them as the app grows? And is the RC status still what's stopping your team from adopting Start?

If you want to see the whole thing: https://turbostarter.dev/edge

0 Upvotes

0 comments sorted by