Written by Huifer, solo developer and maintainer of TanStack Ship. I built TanStack Ship because I shipped 12+ TanStack apps on Cloudflare Workers between 2023 and 2026 and got tired of rewriting the same Stripe webhook handler every time. The commercial layer — the part that turns a deployed app into a paying business — is what cost me the most weekends. This post is the field report from those weekends.
Verified sources: TanStack Start docs · Cloudflare Workers pricing · Cloudflare D1 limits · Stripe webhook signing · TanStack Ship features Last updated: 2026-06-18 · Changelog
TL;DR: A commercial SaaS has three layers — foundation (auth, DB, hosting), commerce loop (Stripe, webhooks, MRR dashboard), and growth loop (UTM capture, referral credits, ROI). Most templates stop at the first layer. TanStack Ship ships all three as 14 production modules on TanStack Start + Cloudflare Workers. The commercial math for a solo founder: ~$5/month hosting at 100k requests versus ~$50 on a Next.js + Vercel + Postgres stack. Below: the layers, the architecture, and the founder-fit decision at the end.
What "Commercial for SaaS" Actually Means — Three Layers, Not One
When a solo founder asks me "is this template commercial-ready?", I translate that into three more honest questions:
- Can I deploy it today and have a real user hit a real Stripe checkout without writing any code?
- Can I see, tomorrow, how much MRR I made, which UTM drove it, and which coupon was redeemed?
- Can I invite another founder to test the product, give them a 20% off code, and watch the credit flow into a referral payout?
Most templates answer "yes" to question one and "no" to questions two and three. That is the gap TanStack Ship was built to close.
Layer 1 — The foundation (auth, DB, hosting)
The foundation is what every template handles: TanStack Router for type-safe routing, Cloudflare D1 for the SQLite-compatible edge database, Better Auth for sessions, R2 for file uploads, and a one-command wrangler deploy. Most "TanStack starters" on GitHub treat it as the entire deliverable. I treat it as roughly 20% of what a commercial SaaS needs. The other 80% is what every comparison post glosses over.
Layer 2 — The commerce loop (Stripe, webhooks, MRR)
This is where most indie founders lose their first weekend. Stripe Checkout is easy. Webhook signature verification on Cloudflare Workers requires careful raw-body handling — I have a postmortem on that failure mode that cost me a Sunday. On top of that you need:
- A webhook handler that is idempotent (Stripe retries on non-2xx)
- A customer portal link flow
- A subscription state machine (
active,trialing,past_due,canceled) - A pricing engine that supports monthly + annual + coupons + referral credits stacking
- An MRR / ARR dashboard that updates from the same database
TanStack Ship ships all five. The pricing engine is a Server Function that takes a context object (user, coupon, credits, UTM) and returns the final price.
// src/server/functions/pricing.ts
import { createServerFn } from "@tanstack/start"
import { getContextPrice } from "@/server/db/pricing"
export const computePrice = createServerFn({ method: "POST" })
.validator((input: { planId: string; couponCode?: string; refCode?: string }) => input)
.handler(async ({ data, context }) => {
const { session } = context
return getContextPrice({
planId: data.planId,
userId: session?.userId ?? null,
couponCode: data.couponCode ?? null,
referralCode: data.refCode ?? null,
utmSource: context.cookies["utm_source"] ?? null,
})
})
The handler returns the discounted price plus a breakdown the checkout UI can render — coupon amount, credit applied, referral discount, UTM source. Stripe Checkout receives the final amount and the breakdown travels into the conversions row.
Layer 3 — The growth loop (UTM, referrals, ROI)
This is the layer that turns a deployed SaaS into a commercial SaaS. Three sub-systems:
- SSR UTM capture:
?utm_source=hn&utm_campaign=launchlands on a landing page that stores the UTM tuple in a first-party cookie. When the visitor converts, the UTM travels with the Stripe event into aconversionstable. - Referral credits: a logged-in user gets a referral code; when a new user signs up via
?ref=…, both accounts receive credits that the pricing engine honors automatically. - Multi-channel ROI dashboard: an admin view that answers "for every $1 I spent on HN, Product Hunt, and Twitter in June, how much MRR came back?"
I shipped this end-to-end on a production app that took in ~$4,200 in June 2026 — 38% traceable to a specific UTM source, 11% from redeemed referral credits. None of that attribution would exist if I had stopped at "Stripe checkout wired up" and skipped the layer below.
Why TanStack-Native Beats Framework-Agnostic
There are two ways to build a SaaS starter today: pick a framework and adapt a generic boilerplate, or pick the TanStack-native architecture and let the toolchain stay consistent from routing to data.
Compile-time type safety across the route
With TanStack Router + Server Functions, a broken link shows up at build time. The route /admin/billing/$invoiceId either resolves to a Server Function returning { amount, currency, status } or the build fails. This sounds small until you have shipped a Next.js app where a renamed server prop deserialized as undefined and blew up at runtime.
// src/routes/admin/billing/$invoiceId.tsx
import { createFileRoute } from "@tanstack/react-router"
import { getInvoice } from "@/server/functions/billing"
export const Route = createFileRoute("/admin/billing/$invoiceId")({
loader: async ({ params }) => getInvoice({ data: { id: params.invoiceId } }),
component: InvoicePage,
})
function InvoicePage() {
const invoice = Route.useLoaderData()
// invoice is fully typed: { amount: number, currency: 'USD' | 'EUR', status: InvoiceStatus }
return <div>{invoice.amount} {invoice.currency} — {invoice.status}</div>
}
The same file works in TanStack Start with SSR streaming — the loader runs on the worker, the component hydrates on the client, and TypeScript checks the contract at both ends. See the TanStack Start docs for streaming and the TanStack Router typegen docs for how $invoiceId is wired through tsr generate.
Edge-native data layer (D1 + R2)
Cloudflare D1 is SQLite at the edge. Each database can be up to 10 GB per the D1 limits docs, with up to 50,000 databases per account and read replicas for horizontal scale. For a solo SaaS that does not need cross-region writes, D1 is the cheapest serious database in 2026 — included in the Workers paid plan at $5/month with zero per-row costs.
R2 is object storage with zero egress fees — the only major cloud object store that does not charge per-GB-out. R2 alone can save $20–$200/month versus S3 or Vercel Blob.
The lock-in math
Lock-in is a real concern with any opinionated template. My honest take: TanStack Ship is more portable than a Next.js + Vercel + Supabase starter.
- Runtime: TanStack Start is a thin layer over Vite. You can move the output to any Node host.
- Database: D1 is SQLite.
wrangler d1 exportloads into any Postgres, MySQL, or Turso instance. - Auth: Better Auth is framework-agnostic. The session table is a normal D1 table.
- Stripe: Stripe is the constant regardless of which template you move to.
The lock-in cost is concentrated in the 14 production modules. Leave TanStack Ship and you do not lose data; you lose 8–12 weekends of rebuilding business logic.
The 14 Production Modules — What They Unlock
Here is the module list as of June 2026. Every module ships with a D1 schema migration, an admin shell page, a Server Function API, and a feature page on this site.
| # | Module | What it does |
|---|---|---|
| 1 | Auth | Email/password + magic link + OAuth via Better Auth |
| 2 | Stripe Billing | Checkout, webhooks, customer portal, idempotent handler |
| 3 | Pricing Engine | Context-aware price computation (coupons, credits, UTM) |
| 4 | UTM Attribution | SSR capture + cookie persistence + conversions table |
| 5 | Referral Credits | Invite codes + dual-side credit ledger |
| 6 | Email Campaigns | HTML editor + Cloudflare Queues async dispatch |
| 7 | MRR / ARR Dashboard | Live computation from the subscriptions table |
| 8 | Blog CMS | MDX + i18n + Shiki + Mermaid |
| 9 | R2 File Manager | Admin file browser + signed URL generation |
| 10 | i18n | Paraglide JS with en / zh / de built-in |
| 11 | Admin Shell | Authenticated dashboard for all modules above |
| 12 | Cron Jobs | Cloudflare Cron Triggers + audit log |
| 13 | API Keys | Per-user scoped tokens for the public API |
| 14 | MCP / WebMCP | Agent protocol surfaces at /.well-known/mcp/* |
The point is not that any single module is novel — you can build any one with a long weekend. The point is that they share a database, an auth context, an admin shell, and a deployment pipeline. You do not get to glue five half-built third-party products together to build a commercial SaaS. You get a single codebase.
The Commercial Math for an Indie Founder
I keep a running spreadsheet of my Cloudflare invoice and Stripe revenue for the TanStack Ship-based apps I run. Here is the monthly cost for one production SaaS at ~100k requests, ~5k active users, ~$2,800 MRR:
| Line item | TanStack Ship (CF stack) | Next.js + Vercel + Postgres |
|---|---|---|
| Hosting | $5 (Workers paid plan) | $25 (Vercel Pro) |
| Database | $0 (D1 included) | $25 (Supabase Pro or Neon Scale) |
| File storage (20 GB) | $0.30 (R2: 20 GB × $0.015) | $20 (Vercel Blob: 20 GB × $1/GB) |
| Email (Resend) | $0 (free tier, 3k/mo) | $0 (same) |
| Stripe fees | 2.9% + 30¢ × ~310 txns ≈ $87 | $87 (same) |
| Total infra + fees | ~$92 | ~$157 |
The $65/month delta is the difference between break-even and a paycheck on the first 100 paying customers. At 1M monthly requests, the gap widens to ~$200/month because Cloudflare egress stays at $0 while Vercel's edge function billing grows roughly linearly with invocations.
TanStack Ship's pricing model is a one-time $149 license — roughly two months of the Cloudflare cost delta. Save one weekend of debugging Stripe webhook idempotency, and the ROI is positive on day one.
I am being deliberately conservative. The published Cloudflare Workers pricing lists the paid plan at $5/month with 10M requests included. At 50M requests/month, you are in the $25–$50 Workers bracket, and the Next.js + Vercel stack is closer to $100–$150.
Who TanStack Ship Is For (and Who It Isn't)
Every boilerplate post should include a fit section, so here is mine.
TanStack Ship is a strong fit if you are:
- A solo developer or two-person team wanting type-safe end-to-end React on a serverless budget
- Comfortable with TanStack Router, or willing to learn it (the typegen takes a morning)
- Deploying a SaaS that needs Stripe + a real admin shell + at least one growth loop on day one
- Comfortable operating inside the Cloudflare ecosystem (Workers, D1, R2, Queues)
TanStack Ship is the wrong template if you are:
- A non-technical founder — try Makerkit or Wasp instead
- A team standardized on Next.js + Vercel + Postgres that does not want to retrain — ShipFast is the right pick
- Building a content-only site with no commerce layer — the TanStack Start docs alone are enough
- Operating a regulated workload (HIPAA, PCI-DSS Level 1) — check the Cloudflare compliance docs before assuming the edge fits
I have also seen teams buy TanStack Ship expecting "a SaaS in a box" and realize they still need to write their core feature. TanStack Ship is the foundation and the business layer — auth, billing, growth, admin. Your product logic is still your job.
Closing — Try the Production Stack
The fastest way to know if TanStack Ship fits your SaaS is to clone it, run pnpm install, and try to break the Stripe webhook handler locally with stripe trigger checkout.session.completed. If the idempotency check holds and the MRR dashboard updates within a second, you have the same foundation I ship daily.
For the full module list, see the TanStack Ship features index or jump to the pricing page. For the trace that convinced me to ship idempotent webhook handling as a default, the Stripe webhook duplicate delivery writeup walks through it.
The 2026 SaaS template market is healthier than ever — ShipFast, Makerkit, Open-SaaS, Turbostarter, and TanStack Ship are all real, production-tested options. Pick the one whose opinions match the ones you will hold for three years. For me, that is TanStack Start + Cloudflare Workers + Stripe + a 14-module foundation I do not have to rebuild every time.