When I first started building SaaS products, I relied heavily on traditional serverless functions for my API routes. It was the default choice. You write a function, deploy it, and call it a day. But as my user base started to spread across different time zones, I ran into a frustrating reality: my API was fast in the US, but painfully slow for users in Europe or Asia.
I was struggling with cold starts and network latency, especially for endpoints that needed to fetch external data. Every time a user ran a site analysis, they were waiting for the request to travel across the world, hit a server in us-east-1, and travel back. So I decided to build something that handled this architecture out of the box, which eventually became the foundation for my TypeScript-first SaaS starter kit, SaaSLaunch.
The Latency Problem in Global SaaS
When you are building a SaaS, performance isn't just a nice-to-have; it's a core part of the user experience. If your tool takes three seconds to return a result because of network latency, users will assume your tool is broken, even if your actual processing logic takes 50 milliseconds.
The cost of ignoring global latency is high. You lose user trust, increase bounce rates, and create a fragmented experience where your app feels "fast" for some and "sluggish" for others.
Traditionally, developers solve this by putting a CDN in front of their static assets, but dynamic API routes are harder to optimize. You generally have two main approaches for dynamic processing:
- Traditional Serverless (e.g., AWS Lambda, Vercel Functions): These run in specific regions. They offer full Node.js compatibility, meaning you can use any npm package. The trade-off is that cold starts can introduce latency, and if your function is deployed in one region, users far away will experience higher network latency.
- Edge Computing (e.g., Cloudflare Workers): These run on a global network of servers. Your code is deployed to hundreds of locations simultaneously. The trade-off is that edge runtimes historically have stricter limits. You can't use heavy Node.js-specific APIs, and you have to be mindful of your bundle size.
Moving to the Edge: Technical Approach
When building the architecture for SaaSLaunch, I needed a way to run an SEO analysis tool that could fetch and parse external websites quickly, no matter where the user was located. Traditional serverless wasn't cutting it for global users.
I decided to use Cloudflare Workers for the edge-side API routes. The goal was to fetch the target HTML at the edge and run basic SEO checks without pulling in heavy dependencies.
Here is a simplified look at how the edge worker handles the 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' },
});
},
};
Let's break down the key decisions here.
First, the fetch call uses Cloudflare's specific cf options. By setting cacheTtl, we can cache the external HTML response at the edge for a few minutes. If multiple users check the same URL, the worker serves it instantly from the edge cache without hitting the origin server again.
Second, notice how the HTML parsing is done. In a traditional Node.js serverless environment, I would reach for a library like cheerio or jsdom to parse the DOM. However, edge runtimes are optimized for small bundle sizes and fast startup times. Pulling in a full DOM parser adds unnecessary weight. Instead, I used targeted regular expressions to extract the title, meta description, and H1 count.
Is regex as robust as a full DOM parser? No. It can break if the HTML is heavily malformed or uses unusual formatting. But for the specific use case of grabbing basic SEO metadata, it is very fast and keeps the worker bundle tiny, which is crucial for edge performance.
Practical Results and Trade-offs
Moving these specific API routes to the edge yielded noticeable improvements. The most obvious win was the latency drop for international users. Because the worker runs in a data center physically closer to the user, the time-to-first-byte for the analysis dropped significantly.
What surprised me was how smooth the integration was with Next.js 14's App Router. Initially, I was worried about the cognitive load of managing two different deployment targets (Vercel for the main app, Cloudflare for the edge workers). But by keeping the edge workers strictly for specific, stateless API routes, the mental model remained simple.
However, it's not a silver bullet. I would change how I initially approached the database connections. Edge runtimes don't support traditional persistent database connections well. For the edge workers, I had to ensure all data fetching was done via HTTP APIs rather than direct database ORM calls.
Also, I kept the Stripe subscription billing webhooks on traditional serverless. Stripe webhooks require robust cryptographic verification and complex database transactions. Trying to shoehorn that into an edge runtime with strict size and execution limits was more trouble than it was worth. It's important to choose the right tool for the specific job.
Checking Your Own SEO at the Edge
If you are curious about how this edge architecture performs in the real world, I built a free SEO checker using this exact Cloudflare Worker setup. It analyzes your landing page for basic metadata, heading structure, and title tags, all processed at the edge for low latency.
You can try it out here: SaaSLaunch Free SEO Checker
Whether you are just checking your own site or looking for inspiration on how to structure your Next.js and Cloudflare architecture, I hope it helps you on your building journey.
Full disclosure: I'm the developer of SaaSLaunch. I built this because I needed it myself.
Top comments (0)