When I first started building SaaS products, I kept running into the same wall. I’d have a great idea for a micro-SaaS, open my editor, and immediately get bogged down in the boilerplate. I was struggling with wiring up Stripe webhooks, configuring NextAuth for OAuth, and figuring out how to keep API routes fast for users outside my home region. Every time I started a new project, I spent the first two weeks just building the plumbing. The actual unique feature of my app wouldn't get written until week three. So I decided to build something to solve this.
The Plumbing Problem
The problem with SaaS boilerplate isn't just that it takes time to write; it's the context switching. When you're in the flow of designing your core product logic, stopping to debug a Stripe webhook signature or tweak a Cloudflare routing rule completely derails your momentum.
But there’s another layer to this: performance. If your SaaS relies on fetching external data, running SEO checks, or processing heavy payloads, standard serverless functions can introduce noticeable latency for global users. Ignoring edge computing means your users in Europe or Asia are waiting on requests routed to a single US data center. In a world where users expect instant feedback, that latency translates directly to abandoned carts and churn. You need a way to handle the heavy, global-facing lifting at the edge, while keeping your core database and stateful logic in a standard serverless environment.
The Technical Approach
To solve this, I architected a stack that splits the workload. The core application uses Next.js 14+ with the App Router, handling authentication via NextAuth.js and managing stateful data. For billing, we use Stripe. For global, read-heavy, or external-fetch tasks, we offload to Cloudflare Workers.
Let’s look at how the billing integration works in the Next.js App Router. Setting up Stripe checkout requires creating a session and redirecting the user. Here is the TypeScript API route I use to handle this:
// Next.js API route for Stripe checkout (App Router)
import { NextResponse } from 'next/server';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { priceId, userId } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.APP_URL}/dashboard?success=true`,
cancel_url: `${process.env.APP_URL}/pricing?cancelled=true`,
client_reference_id: userId,
});
return NextResponse.json({ url: session.url });
}
This keeps the checkout flow clean. The client_reference_id is crucial here—it allows us to map the Stripe session back to our internal user ID when the webhook fires later.
Now, for the edge computing part. I wanted to build a built-in SEO checker that analyzes landing pages without the latency of a traditional backend. By deploying this as a Cloudflare Worker, the code runs in data centers all over the world. Here is the worker logic for the edge SEO analysis:
// Cloudflare Worker for edge SEO analysis
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname !== '/api/analyze') {
return new Response('Not found', { status: 404 });
}
const targetUrl = url.searchParams.get('url');
if (!targetUrl) {
return new Response(JSON.stringify({ error: 'Missing url' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// Fetch target page at the edge (low latency worldwide)
const response = await fetch(targetUrl, {
cf: { cacheTtl: 300, cacheEverything: true },
});
const html = await response.text();
// Run SEO checks (regex-based, no DOM needed)
const title = html.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1] || '';
const desc = html.match(/<meta[^>]*name=["']description["'][^>]*content=["']([^"']*)["']/i)?.[1] || '';
const h1Count = (html.match(/<h1[ >]/gi) || []).length;
return new Response(JSON.stringify({ title, desc, h1Count }), {
headers: { 'Content-Type': 'application/json' },
});
},
};
Notice how we use Cloudflare's specific cf object in the fetch request. This allows us to cache the target page at the edge for 300 seconds. The regex-based parsing is intentionally lightweight; we don't need a full DOM parser at the edge, just the core meta tags and heading counts. This approach keeps the worker execution time well under the free tier limits while providing incredibly fast response times globally.
The trade-off here is complexity in deployment. You have to manage two environments: Vercel for the Next.js app and Cloudflare for the Workers. However, by setting up one-click deployments for both, the initial setup cost is a one-time pain that pays off in long-term performance.
Practical Results
What worked exceptionally well was the separation of concerns. Keeping the database and auth on standard serverless while pushing the SEO analyzer to the edge meant the app feels incredibly snappy for global users. The SEO tool, in particular, became a favorite feature because it returns results almost instantly, regardless of where the user is calling it from.
What surprised me was how much time the integrated webhook handling saved. Because the Stripe checkout and webhook listeners were built into the same repository from day one, I didn't have to hunt down environment variable mismatches between my local dev environment and production.
If I were to change anything, I’d probably abstract the Stripe webhook signature verification into a reusable middleware right from the start. In the early days of building this, I had to patch it in a few times to handle edge cases with Stripe's test events. It’s a minor detail, but in a boilerplate, those minor details are what make the difference between a good starter kit and a great one.
Try It Yourself
If you're building a SaaS and want to test how your landing page performs globally, or if you just want to see how the edge SEO tool works in practice, I've made it available for free. You can try the SEO Checker at saaslaunch.dev/free-tools/seo-checker. It runs on the exact same Cloudflare Worker architecture I walked through above, so you can see the edge performance firsthand.
If you end up building your own SaaS and want to skip the two-week plumbing phase, the full SaaSLaunch starter kit includes this edge setup, Next.js 14 App Router, and Stripe billing out of the box.
Full disclosure: I'm the developer of SaaSLaunch. I built this because I needed it myself.
Top comments (0)