Skip to main content

Edge-First SaaS Boilerplates 2026

·StarterPick Team
cloudflare-workersd1edgesaasboilerplate2026

TL;DR

Edge-first SaaS means your code runs in 300+ locations worldwide — millisecond latency for every user, zero cold starts, and infrastructure costs that scale to near-zero at low traffic. The tradeoff: you're constrained by the Workers runtime (no Node.js APIs, limited duration) and the D1 SQLite database is still maturing. For global B2B SaaS, API products, and developer tools, the edge stack is increasingly compelling. For monolithic CRUD apps with complex SQL, traditional cloud is still better.

Key Takeaways

  • Cloudflare Workers free tier: 100k requests/day with zero cold starts — best free tier in serverless
  • D1 (SQLite) is Cloudflare's edge database — free tier is generous, production readiness is solid as of 2026
  • Hono is the dominant micro-framework for Workers (and Bun/Deno/Node — runs anywhere)
  • KV (key-value store) and R2 (object storage) complete the edge storage stack at low cost
  • No full-stack boilerplate like ShipFast exists yet — you're assembling from primitives
  • Best for: API products, global B2B SaaS, developer tools, webhooks at scale

The Edge Stack Components

Compute:     Cloudflare Workers (JavaScript/TypeScript, V8 isolates)
Database:    D1 (SQLite at the edge, replicated globally)
Cache/State: KV (eventually consistent, global)
Storage:     R2 (S3-compatible, zero egress fees)
Auth:        Clerk + Workers, or DIY with KV sessions
Queue:       Queues (Workers Queue for async jobs)
Email:       Resend or Mailchannels (Workers integration)
AI:          Workers AI (GPU inference at the edge)

Pricing snapshot (2026):

ServiceFree TierPaid
Workers100k req/day$5/month + $0.50/M requests
D15M reads, 100k writes/day$0.001/M reads
KV100k reads, 1k writes/day$0.50/M reads
R210GB storage$0.015/GB
Queues1M operations/month$0.40/M ops

Why Edge for SaaS?

Traditional SaaS deploys to a single region (us-east-1 is the joke). Users in Singapore, London, or São Paulo experience 200-400ms latency before your code even starts running. Edge-first inverts this: your code runs in the datacenter closest to the user.

Practical impact:

ArchitectureUser in Singapore (origin: US)
Traditional (Vercel, Railway)180-300ms p95
Edge-first (Cloudflare Workers)15-50ms p95

For API products, developer tools, and B2B SaaS where speed is a differentiator, this matters.


Hono — The Edge-Native Framework

Hono is the framework of choice for Cloudflare Workers SaaS. It's ultra-lightweight (~14kB), runs on any JavaScript runtime (Workers, Bun, Deno, Node), and has a Next.js-style API for SSR.

// worker.ts — complete Hono app on Cloudflare Workers
import { Hono } from "hono";
import { clerkMiddleware, getAuth } from "@hono/clerk-auth";
import { cors } from "hono/cors";

type Env = {
  DB: D1Database;
  KV: KVNamespace;
  CLERK_SECRET_KEY: string;
};

const app = new Hono<{ Bindings: Env }>();

app.use("*", cors());
app.use("/api/*", clerkMiddleware());

// D1 query
app.get("/api/projects", async (c) => {
  const { userId } = getAuth(c);
  if (!userId) return c.json({ error: "Unauthorized" }, 401);

  const { results } = await c.env.DB.prepare(
    "SELECT * FROM projects WHERE user_id = ? ORDER BY created_at DESC"
  )
    .bind(userId)
    .all();

  return c.json({ projects: results });
});

// KV caching
app.get("/api/config/:key", async (c) => {
  const cached = await c.env.KV.get(c.req.param("key"));
  if (cached) return c.json(JSON.parse(cached));

  const config = await getConfig(c.req.param("key"));
  await c.env.KV.put(c.req.param("key"), JSON.stringify(config), { expirationTtl: 3600 });
  return c.json(config);
});

export default app;

Notable Edge-First SaaS Starters

1. hono-workers-saas (Community)

The most complete free edge SaaS starter. Stack:

  • Hono on Cloudflare Workers
  • D1 (SQLite via Drizzle ORM)
  • Clerk authentication
  • Stripe billing
  • React frontend (served from Workers)
  • KV for session caching
npm create cloudflare@latest my-saas -- --template=hono

2. create-cloudflare + Hono (Official)

Cloudflare's official starter, then add Hono:

# Official Cloudflare starter
npm create cloudflare@latest my-app -- --type=hello-world

# Add Hono
npm install hono @hono/zod-validator zod

# Add D1
wrangler d1 create my-saas-db

3. Remix + Cloudflare Workers

Remix has first-class Cloudflare Workers support:

npx create-remix@latest --template cloudflare-workers

This gives you Remix's nested routing and data loading on the edge. Pair with D1 via Drizzle for a complete stack.

4. Next.js + Cloudflare (via next-on-pages)

npm create cloudflare@latest my-next-app -- --framework=next

Limited: Next.js on Workers uses the Edge Runtime, which doesn't support all Node.js APIs. Better as a static/hybrid than full server app.

5. workers-sdk SaaS Template

wrangler generate my-saas cloudflare/workers-sdk/templates/worker-typescript

Minimal TypeScript starter, no framework. Good for API products where you want full control.


D1 Database Patterns

D1 is SQLite, which means:

  • ✅ Fast reads (SQLite is remarkably fast)
  • ✅ ACID transactions
  • ✅ Standard SQL syntax
  • ❌ No complex JSON aggregations (limited JSONEach etc)
  • ❌ Single-writer model (no concurrent writes from multiple processes)

Drizzle + D1

// db/schema.ts
import { sqliteTable, text, integer, real } from "drizzle-orm/sqlite-core";

export const subscriptions = sqliteTable("subscriptions", {
  id: text("id").primaryKey(),
  userId: text("user_id").notNull(),
  stripeSubscriptionId: text("stripe_subscription_id"),
  status: text("status").notNull().default("free"),
  currentPeriodEnd: integer("current_period_end"),
});

// worker.ts
import { drizzle } from "drizzle-orm/d1";

app.get("/api/subscription", async (c) => {
  const db = drizzle(c.env.DB);
  const { userId } = getAuth(c);

  const [subscription] = await db
    .select()
    .from(subscriptions)
    .where(eq(subscriptions.userId, userId!));

  return c.json(subscription ?? { status: "free" });
});

Migration workflow

# Create migration
npx drizzle-kit generate

# Apply to local D1
wrangler d1 execute my-saas-db --local --file=./drizzle/migrations/0001_add_subscriptions.sql

# Apply to production D1
wrangler d1 execute my-saas-db --file=./drizzle/migrations/0001_add_subscriptions.sql

Authentication on the Edge

Clerk (Easiest)

import { clerkMiddleware, getAuth } from "@hono/clerk-auth";

app.use("*", clerkMiddleware());

app.get("/api/me", async (c) => {
  const { userId } = getAuth(c);
  if (!userId) return c.json({ error: "Unauthorized" }, 401);
  return c.json({ userId });
});

wrangler.toml:

[vars]
CLERK_SECRET_KEY = "sk_..."
CLERK_PUBLISHABLE_KEY = "pk_..."

DIY Session Auth (No third party)

// Store sessions in KV
async function createSession(userId: string, kv: KVNamespace) {
  const sessionId = crypto.randomUUID();
  await kv.put(`session:${sessionId}`, userId, { expirationTtl: 86400 * 7 });
  return sessionId;
}

async function getSession(sessionId: string, kv: KVNamespace) {
  return kv.get(`session:${sessionId}`);
}

KV sessions are globally consistent within ~60 seconds — fine for most SaaS auth flows.


Billing at the Edge

Stripe works fine from Workers — it's just HTTPS requests. The main consideration is webhook handling:

// Stripe webhook handler on Workers
app.post("/webhooks/stripe", async (c) => {
  const signature = c.req.header("stripe-signature")!;
  const body = await c.req.text();

  const event = await stripe.webhooks.constructEventAsync(
    body,
    signature,
    c.env.STRIPE_WEBHOOK_SECRET
  );

  if (event.type === "customer.subscription.updated") {
    const sub = event.data.object;
    const db = drizzle(c.env.DB);
    await db
      .update(subscriptions)
      .set({ status: sub.status, currentPeriodEnd: sub.current_period_end })
      .where(eq(subscriptions.stripeSubscriptionId, sub.id));
  }

  return c.json({ received: true });
});

Edge-First vs Traditional: Honest Comparison

ConsiderationEdge-FirstTraditional (Vercel/Railway)
Global latency✅ 15-50ms everywhere⚠️ 50-300ms outside origin region
Cold starts✅ None (V8 isolates)⚠️ 200-2000ms (varies)
Node.js APIs❌ Not available✅ Full Node.js
Database options🟡 D1 (SQLite)✅ Postgres, MySQL, MongoDB
Ecosystem maturity🟡 Growing✅ Mature
Boilerplate options🟡 Few✅ Many (ShipFast, Makerkit, etc.)
Max execution time30s (CPU time)Unlimited (Vercel Pro)
Cost at scale✅ Very low✅ Reasonable
Cost at zero scale✅ Free✅ Free (most have free tiers)

Bottom line: Edge-first is a specialized choice. Pick it when global latency matters to your users or when you're building an API product where sub-50ms response times are a selling point.


For a production-ready edge SaaS in 2026:

# Scaffold
npm create cloudflare@latest my-saas -- --type=hello-world

# Install dependencies
npm install hono @hono/clerk-auth drizzle-orm stripe resend zod

# Create D1 database
wrangler d1 create my-saas-db

# Set up R2 bucket (file uploads)
wrangler r2 bucket create my-saas-uploads

wrangler.toml:

name = "my-saas"
main = "src/worker.ts"
compatibility_date = "2025-09-01"

[[d1_databases]]
binding = "DB"
database_name = "my-saas-db"
database_id = "..."

[[kv_namespaces]]
binding = "KV"
id = "..."

[[r2_buckets]]
binding = "FILES"
bucket_name = "my-saas-uploads"

Total infrastructure cost at launch: $0/month (well within Workers + D1 + KV free tiers).


Methodology

  • Analyzed Cloudflare pricing pages, D1 documentation, and Workers limits as of March 2026
  • Tested Hono on Workers with D1 and Drizzle in local development
  • Reviewed community starters on GitHub (GitHub search + Cloudflare Discord)
  • Compared Workers runtime constraints vs Node.js environment
  • Reviewed Remix, Next.js, and Hono on Workers deployment guides

Compare all Cloudflare Workers and edge-first starters on StarterPick.

Comments