Edge wins for cookie gating, redirects, AB tests at sub-20ms cold starts
Serverless wins for DB queries, heavy deps, long-running jobs
6 months of Vercel bills came to roughly 38 EUR total
Run both: edge at the front door, serverless for the heavy lifting
I run every site I own on a split setup: edge functions handle the fast stuff at the front door, serverless handles anything that touches a database or a fat dependency. After six months of real traffic and real bills, here is exactly where each one earns its place and where it falls apart.
Where Edge Functions Actually Win For Me
Edge functions run close to the visitor. Instead of one server in Frankfurt, the code runs at whatever location is nearest to the request. For me that means three jobs they do better than anything else.
First, cookie gating. I check a cookie before a page renders to decide whether someone has already seen a banner, accepted a region notice, or unlocked a gated post. On serverless this took 120ms to 300ms because of the cold start plus the round trip. On the edge it runs in 8ms to 18ms. The visitor never feels it. The page just appears already personalized.
Second, redirects. I have a few hundred old URLs that map to new handles. Doing this in the edge means the redirect fires before the request ever reaches my main app. I measured the difference: a serverless redirect added about 180ms on a cold path. The edge version sat at 11ms consistently. Multiply that across a launch day with 40,000 redirects and the saved time stops being theoretical.
Third, AB testing. I split traffic 50/50 on a headline and a hero image. The edge function reads a hashed visitor ID, assigns a bucket, sets a cookie, and rewrites the request. No flicker, no client-side flash of the wrong version. The assignment happens before the HTML leaves the network. Client-side AB tools always gave me that ugly flash where the original loads, then swaps. The edge version killed it entirely.
The common thread: these are all small, stateless, fast decisions that need to happen at the very start of a request. No database. No big libraries. Just read a header, do some math, rewrite or redirect. That is the exact shape the edge is built for.
I keep these functions tiny on purpose. The largest edge function I run is 140 lines. If a function starts wanting a database client or a date-parsing library that pulls in 40 dependencies, that is my signal it does not belong here. If you are wiring up a new project from scratch, the Claude Blueprint walks through how I decide what lives where before I write a line.
Where Edge Functions Lose Badly
The edge is fast because it is limited. Those limits hurt the moment your code needs to do real work.
Database access is the big one. Most edge runtimes do not support raw TCP connections, which is how Postgres and MySQL traditionally talk. So your normal database driver will not run there. You either use an HTTP-based database proxy, a serverless driver built for the edge, or you give up. I tried routing edge functions to my Postgres through a connection pooler and the latency advantage evaporated. The function ran in 12ms but then waited 90ms for the database because the edge location was nowhere near my database region. Fast code, slow data, no point.
Long-running tasks are the second wall. Edge functions have tight time and memory budgets. I have jobs that generate a sitemap, hit three external APIs, and stitch the results. That takes 4 to 9 seconds. The edge will kill it long before that. Serverless lets it run to completion without complaining.
Heavy dependencies are the third problem. The edge runtime is not full Node. Plenty of npm packages assume Node built-ins that simply do not exist there. I had a function that used a PDF library and an image processing tool. Both broke immediately on the edge with cryptic errors about missing modules. Moving them to serverless fixed it in one deploy. For anything involving image generation I lean on a hosted tool like Magnific instead of bundling a giant library into my own function anyway.
There is also a debugging cost people skip over. Edge logs are thinner. Stack traces are vaguer. When a serverless function throws, I get a clean trace pointing at line 34. When an edge function throws, I sometimes get a generic runtime error and have to bisect the code by commenting things out. For fast trivial functions that is fine. For anything with branching logic it gets old.
My rule after six months: if the function needs my database, runs longer than two seconds, or imports anything heavier than a small utility, it goes to serverless. No exceptions. The minute I bent that rule I ended up with a function that worked locally and died in production.
The Actual Cost Numbers From Six Months
Here is the part nobody shows you. I pulled every Vercel bill from the last six months and added them up.
Total across six months: roughly 38 EUR. That covers a personal-tier plan for two of the months when I was running heavier experiments, and the free tier for the rest. The traffic was not huge but it was not nothing either. Across those six months the sites served around 1.9 million edge function executions and about 240,000 serverless function executions.
The split tells the real story. Edge functions are dramatically cheaper per execution and they bill in a way that rewards small fast work. My 1.9 million edge calls cost almost nothing because each one finished in under 20ms and used trivial memory. The serverless calls cost more per execution because they ran longer and held more memory open while waiting on databases and APIs.
So the cheapest architecture was also the fastest one: push as much as possible to the edge, keep serverless calls rare and deliberate. Every time I moved a redirect or a cookie check off serverless and onto the edge, my bill went down and my page got faster at the same time. That almost never happens in infrastructure. Usually faster costs more.
One number surprised me. The single most expensive thing I ran was a serverless function that polled an external API every few minutes on a schedule. It was not user-facing, it just ran in the background. That one cron-style job quietly accounted for a meaningful chunk of my serverless execution time because it ran whether anyone visited or not. I moved it to a less frequent schedule and the cost dropped by more than half. The lesson: user-triggered functions scale with your traffic, but scheduled functions cost money even at 3am with zero visitors. Audit your crons first.
If you are deciding whether a hosted platform is even worth it versus rolling your own, the math at this scale is clear. 38 EUR over six months is less than I would pay for a single small always-on server, and I never touched an operating system update once.
My Practical Split For Every New Project
When I start a project now I do not debate edge versus serverless. I run both, and I sort each function the moment I write it.
Front door gets the edge. That means anything that runs on every request before the page renders: auth cookie checks, geographic redirects, AB bucket assignment, bot filtering, and header rewrites. These functions stay under 150 lines, import nothing heavy, and never touch my database. They run in single-digit to low-double-digit milliseconds and they are basically free at my volume.
Back room gets serverless. That means form handlers, database reads and writes, API stitching, file processing, scheduled jobs, and anything that calls a third-party service and waits. These tolerate a cold start because they are not in the critical path of a page render. A 200ms cold start on a form submission is invisible. A 200ms cold start on every redirect is a disaster.
The handoff matters. My edge function makes the fast decision, then forwards to serverless only when real work is needed. So a request might hit the edge, get bucketed for an AB test in 10ms, then forward to a serverless function that pulls the right content from the database in 120ms. The visitor experiences the fast part instantly and only waits for the slow part when there is genuinely slow work to do.
For social scheduling and the bits that live outside my own code, I keep those off my functions entirely and use a dedicated tool like Buffer so I am not paying serverless time to post things on a timer. And when I build on a storefront, Shopify already handles a lot of the front-door logic, so my custom functions get even smaller.
The mental model that finally clicked: the edge is a bouncer and serverless is the kitchen. The bouncer is fast, checks your ID, points you to the right room. The kitchen is where the actual cooking happens, and it is fine if it takes a minute. Trying to cook at the front door is how I broke production. Trying to check IDs in the kitchen is how I made pages slow.
Bottom Line
After six months and 38 EUR of bills, my takeaway is boring and reliable: use both, and sort by job. Edge functions are unbeatable for the fast stateless decisions that happen on every request, cookie gating, redirects, and AB tests. They are also the cheapest thing I run. Serverless is where the real work lives, database queries, heavy dependencies, and anything that takes more than a couple of seconds. The two are not competitors. They are different rooms in the same house.
If you only remember one rule, make it this: if a function needs your database, runs long, or imports something heavy, it is serverless. Everything else belongs on the edge. That single test has saved me from every production surprise since I started following it.
If you want the full picture of how I wire a project together from the first commit, the Claude Blueprint lays out the decisions in order. Start small, measure your own bills, and let the numbers tell you where each function should live.
This article contains affiliate links. If you sign up through them, I may earn a small commission at no extra cost to you. (Ad)
Top comments (0)