DEV Community

seller-mind
seller-mind

Posted on

Comparing Edge and Serverless: What I Learned Building SaaS

When I first started building SaaS tools, I relied heavily on traditional serverless functions. Everything was fine until I tried to build a real-time SEO analyzer. Fetching external pages, parsing HTML, and returning results from a single central region meant my users in Europe and Asia were staring at loading spinners for several seconds. I tried optimizing the code, minifying the payloads, and tweaking the database queries, but the network latency was the real bottleneck. I realized that if I wanted to build fast, global SaaS tools, I needed to rethink my architecture entirely. So I decided to build something.

The Hidden Cost of Latency in SaaS

In the SaaS world, performance isn't just a nice-to-have; it's a core feature. When you're building tools that interact with external APIs or fetch live data, every millisecond counts. The problem with traditional serverless setups is that they often route all traffic through a single primary region. If your function needs to fetch a webpage to check its meta tags, that fetch travels from the user, to the serverless region, to the target website, and back.

Ignoring this architectural reality means a poor user experience, higher egress costs, and frustrated users. For billing integrations, slow webhook processing can even lead to missed payment events if timeouts occur. I needed an approach that processed data closer to the user, without sacrificing the rich ecosystem I was used to.

Comparing the Approaches: Edge vs. Serverless

This led me to deeply compare edge computing (specifically Cloudflare Workers) against traditional serverless platforms like Vercel or AWS Lambda. The trade-offs between the two are significant, and neither is a silver bullet.

Serverless is fantastic for heavy compute tasks, complex database operations, and has a incredibly mature ecosystem. However, edge computing shines for I/O-bound tasks like fetching web pages, handling lightweight API requests, and serving global users with low latency.

For the SEO checking tool in my SaaS starter kit, I moved the HTML fetching and parsing to the edge. Instead of a central server doing the work, the request hits the nearest edge node. Here is what the edge worker looks like in practice:

// 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' },
    });
  },
};
Enter fullscreen mode Exit fullscreen mode

The magic here is in the fetch configuration. By passing Cloudflare-specific cf options, we can cache the target page right at the edge for a few minutes. This drastically reduces the load on the target website and speeds up subsequent checks. Furthermore, because we are at the edge, we can't use heavy Node.js libraries like JSDOM. Instead, I used simple regex to extract the title, description, and H1 count. This keeps the worker incredibly lightweight and fast.

But edge computing isn't perfect. You have smaller memory limits and can't use heavy Node.js modules. That's why I adopted a hybrid approach. I kept the heavy Stripe subscription billing logic and NextAuth.js authentication on Next.js 14+ App Router API routes (running on serverless infrastructure), while pushing the I/O-heavy SEO checks to Cloudflare Workers.

Setting up the Stripe checkout in the Next.js serverless environment looks like 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 });
}
Enter fullscreen mode Exit fullscreen mode

By splitting the workload, I get the best of both worlds: robust, ecosystem-rich serverless functions for complex business logic, and blazing-fast edge functions for global, I/O-heavy tasks.

Practical Results and Takeaways

Moving the SEO analysis to the edge drastically reduced the time-to-first-byte for global users. What surprised me was how much simpler the deployment became. By using Cloudflare Workers for the edge APIs and Next.js for the frontend and Stripe webhooks, I could deploy the whole TypeScript-first stack with a single click to either Vercel or Cloudflare Pages.

If I were to change one thing, I'd spend more time upfront designing the caching strategy. Initially, I cached everything aggressively, which meant users sometimes saw stale SEO data when checking a page they had just updated. Tuning the cacheTtl to just a few minutes struck the right balance between performance and data freshness.

Another lesson learned was the importance of full type safety across the boundary. Sharing TypeScript interfaces between the Next.js frontend and the Cloudflare Worker API prevented a lot of integration bugs that usually pop up when mixing different runtime environments.

Try It Yourself

If you're curious about how edge caching and HTML parsing perform in the real world, I put together a free SEO checker using this exact architecture. You can drop in any URL and see the edge-analyzed results instantly, experiencing the low latency firsthand.

You can try the free SEO checker here: https://saaslaunch.dev/free-tools/seo-checker


Full disclosure: I'm the developer of SaaSLaunch. I built this because I needed it myself.

Top comments (0)