Technology·14 min read

Edge Functions vs Serverless vs Containers: Where to Run Code

Your code has to run somewhere. Choosing between edge functions, serverless, and containers determines your latency, costs, and operational complexity for years to come.

Nate Laquis

Nate Laquis

Founder & CEO

Three Runtime Models, Three Sets of Tradeoffs

Every line of backend code you write eventually runs on a machine somewhere. The question that defines your architecture is: which kind of machine, managed by whom, and how close to your users?

In 2026 there are three dominant answers. Edge functions execute on globally distributed runtimes within milliseconds of the end user. Serverless functions run in a single cloud region, scaling to zero when idle and spinning up on demand. Containers give you a full Linux environment that you package once and deploy wherever you want, from a single VM to a Kubernetes cluster spanning five continents.

Each model optimizes for a different constraint. Edge functions optimize for latency. Serverless optimizes for operational simplicity at low to moderate scale. Containers optimize for control, portability, and the ability to run literally any workload you can imagine. Picking the wrong one does not just hurt performance. It inflates your cloud bill, slows your team down, and creates migration headaches that compound every quarter.

This guide breaks down the real differences with actual numbers, not marketing benchmarks. We will cover cold start latency, cost curves at different traffic levels, runtime limitations that bite you six months in, and a practical decision framework you can apply to your own stack today.

Global network connections illustrating edge computing and distributed infrastructure

Edge Functions: Speed at the Network Perimeter

Edge functions run your code at hundreds of points of presence (PoPs) around the world. When a user in Sydney makes a request, the code executes at a data center in Sydney, not in us-east-1. The result is single-digit millisecond cold starts and sub-50ms response times for lightweight logic.

The three major platforms in this space are Cloudflare Workers, Vercel Edge Functions, and Deno Deploy. Cloudflare Workers pioneered the V8-isolate model, running your JavaScript or TypeScript inside the same engine that powers Chrome. There is no container to boot, no runtime to initialize. An isolate spins up in under 5ms. Cloudflare operates 300+ edge locations, and every deployment is live at all of them simultaneously.

Vercel Edge Functions ride on Cloudflare's network but integrate tightly with Next.js. You mark a route handler with `export const runtime = "edge"` and the framework does the rest. Deno Deploy takes a similar approach with its own globally distributed V8 runtime, offering native TypeScript support and Web Standard APIs out of the box.

Where Edge Functions Shine

  • Authentication and session validation. Checking a JWT or session cookie at the edge adds zero perceptible latency. Users never wait for a round trip to your origin server.
  • A/B testing and feature flags. Rewriting responses or injecting headers at the edge means your experiments do not slow down page loads.
  • Geo-routing and personalization. Serving region-specific content, currency, or language without a centralized API call.
  • API gateway logic. Rate limiting, request validation, and header manipulation are perfect edge workloads.

Where Edge Functions Fall Short

The V8 isolate model imposes hard constraints. Cloudflare Workers get 10ms of CPU time on the free tier and 30 seconds on the paid plan. Memory caps at 128MB. You cannot use most Node.js native modules because Workers use Web Standard APIs, not the Node.js runtime. File system access does not exist. If your code needs to parse a 50MB CSV, run a machine learning model, or connect to a database over a long-lived TCP connection, the edge is the wrong place.

Data locality is the other major concern. Your code runs globally, but your database almost certainly does not. A Worker in Tokyo that queries a Postgres instance in Virginia still pays the 150ms+ round-trip penalty. Edge databases like Cloudflare D1, Turso (libSQL), and PlanetScale with read replicas are closing this gap, but they come with their own consistency tradeoffs. For a deeper comparison of specific edge platforms, see our breakdown of Cloudflare Workers vs AWS Lambda vs Vercel Edge Functions.

Serverless Functions: The Regional Workhorse

Serverless functions (AWS Lambda, Google Cloud Functions, Azure Functions) run in a single cloud region, scale automatically from zero to thousands of concurrent instances, and bill you only for execution time. They have been the default backend choice for startups since roughly 2018, and for good reason: you write a function, deploy it, and never think about servers.

AWS Lambda dominates the market. It supports Node.js, Python, Java, Go, .NET, Ruby, and custom runtimes via container images. Execution time can stretch to 15 minutes. Memory goes up to 10GB. You get full access to the Node.js standard library, native npm packages, and the entire AWS ecosystem of 200+ services. Google Cloud Functions offers a similar model with tighter GCP integration, while Azure Functions adds durable function orchestration patterns that are genuinely useful for multi-step workflows.

Cost Model

Lambda charges $0.20 per million requests plus $0.0000166667 per GB-second of compute. At low traffic (under 1M requests per month), you are essentially running for free thanks to the always-free tier. At moderate traffic (10M requests/month at 128MB and 100ms average), you pay roughly $20/month. At high traffic (100M requests/month), costs climb to $200+ and you start to wonder whether a container running 24/7 would be cheaper. The answer is often yes, which is the fundamental tension of the serverless pricing model.

Google Cloud Functions uses a similar pricing structure, with slight differences in per-invocation and per-GB-second rates. Both platforms offer committed use discounts, but these negate the core serverless benefit of paying only for what you use.

The Cold Start Reality

Cold starts remain the most debated aspect of serverless. A Node.js Lambda with a small bundle (under 5MB) cold starts in 200 to 500ms. Add a VPC connection and that jumps to 500ms to 1.5s. Java and .NET runtimes routinely exceed 3 to 5 seconds. Python sits somewhere in between at 300 to 800ms depending on package size.

AWS offers provisioned concurrency to eliminate cold starts entirely, but it changes the economics. You are now paying for always-on capacity, which is effectively the container model with extra overhead. For most startups, the practical approach is to keep Lambda bundles small, avoid VPC attachment unless necessary, and accept that a small percentage of requests will be slower than average.

When Serverless Makes Sense

  • Event-driven architectures. Processing S3 uploads, SQS messages, DynamoDB streams, or webhook payloads. Serverless was designed for this pattern.
  • Background jobs. Sending emails, generating reports, processing payments. These do not need sub-50ms latency.
  • API backends at low to moderate traffic. Under 10M requests/month, serverless is almost always cheaper than containers.
  • Prototyping and MVPs. Zero infrastructure management means your team ships features instead of configuring load balancers.
Data center servers powering serverless cloud computing infrastructure

Containers: Full Control, Maximum Flexibility

Containers package your application, its dependencies, and its runtime into a single image that runs identically on your laptop, in CI, and in production. Docker standardized the format. Kubernetes orchestrates containers at scale. And managed services like Google Cloud Run, AWS Fargate, and Azure Container Apps offer a middle ground where you bring the container and the platform handles the infrastructure.

The container model gives you something edge functions and serverless cannot: a full Linux environment with no arbitrary restrictions on CPU time, memory, network access, or file system usage. You can run a Python ML model that consumes 8GB of RAM. You can maintain persistent WebSocket connections. You can spawn child processes, write to disk, and use any programming language or framework ever created.

Google Cloud Run: The Best of Both Worlds

Cloud Run deserves special attention because it bridges the gap between serverless and containers. You deploy a Docker container, and Cloud Run scales it from zero to thousands of instances automatically. You pay only for request-handling time (with a minimum instance option to avoid cold starts). Cold starts are 500ms to 2s depending on image size, which is slower than Lambda but manageable for most workloads.

Cloud Run pricing is competitive: $0.00002400 per vCPU-second and $0.00000250 per GiB-second. For a service handling 10M requests/month with an average 200ms response time, expect to pay $30 to $60/month. The per-request overhead is lower than Lambda at scale because you can process concurrent requests within a single instance (up to 1,000 concurrent requests per container).

Kubernetes: Power and Complexity

Kubernetes gives you the most control over container orchestration. Auto-scaling, rolling deployments, service mesh, secrets management, and resource quotas are all built in. Managed Kubernetes services (EKS, GKE, AKS) remove the burden of managing the control plane, but you still need to configure node pools, define resource requests and limits, write Helm charts or Kustomize overlays, and monitor cluster health.

For teams under 10 engineers, Kubernetes is almost always overkill. The operational overhead consumes engineering hours that should go toward building product. For teams above 20 engineers running multiple services with complex networking requirements, Kubernetes starts to pay for itself through standardized deployment patterns and efficient resource utilization. We cover this tradeoff in depth in our guide on Kubernetes vs serverless.

When Containers Win

  • Long-running processes. WebSocket servers, background workers, queue consumers, and cron jobs that exceed serverless time limits.
  • ML inference. Loading a model into memory once and serving predictions across many requests is dramatically more efficient than cold-loading on every Lambda invocation.
  • High-traffic APIs. Above 50M requests/month, a container running 24/7 on reserved capacity is typically 50 to 70% cheaper than equivalent serverless compute.
  • Complex runtime requirements. Native binaries, GPU access, custom system libraries, or languages not supported by serverless platforms.
  • Portability. A Docker image runs on any cloud, any on-premise server, or your laptop. No vendor lock-in.

Cold Start Latency and Cost Comparison

Numbers matter more than narratives when you are choosing infrastructure. Here is how the three models compare on the two metrics that affect your users and your wallet most directly.

Cold Start Latency

  • Cloudflare Workers: under 5ms. V8 isolates have no meaningful cold start. Every request is fast.
  • Vercel Edge Functions: under 5ms. Same V8 isolate technology as Workers.
  • Deno Deploy: under 10ms. Slightly higher than Workers but still negligible.
  • AWS Lambda (Node.js, no VPC): 200 to 500ms. Acceptable for most API workloads.
  • AWS Lambda (Node.js, with VPC): 500ms to 1.5s. VPC ENI attachment adds significant overhead.
  • AWS Lambda (Java/.NET): 3 to 8s. Unacceptable for user-facing APIs without provisioned concurrency.
  • Google Cloud Functions (Node.js): 300 to 700ms. Comparable to Lambda.
  • Google Cloud Run: 500ms to 2s. Depends on container image size and startup time.
  • Kubernetes pod (pre-scheduled): 0ms. Pods are already running. No cold start.
  • Kubernetes pod (scaling from zero): 5 to 30s. Node provisioning plus pod scheduling plus container pull.

Monthly Cost at Different Scales

Assuming a typical API workload: 128MB memory for serverless, 0.25 vCPU / 512MB for containers, 100ms average execution time.

  • 1M requests/month: Cloudflare Workers: $0 (free tier). Lambda: $0.40. Cloud Run: $1.50. Kubernetes (always-on): $15 to $30.
  • 10M requests/month: Workers: $5. Lambda: $20. Cloud Run: $15. Kubernetes: $30 to $50.
  • 100M requests/month: Workers: $50. Lambda: $200. Cloud Run: $80. Kubernetes: $60 to $100.
  • 1B requests/month: Workers: $500. Lambda: $2,000+. Cloud Run: $600. Kubernetes: $200 to $400.

The pattern is clear. Edge functions are cheapest at every scale for lightweight compute. Serverless is cost-effective up to moderate traffic, then becomes expensive. Containers have higher baseline costs but flatten at scale because you are paying for reserved capacity, not per-invocation pricing. At extremely high traffic, Kubernetes on reserved instances is the cheapest option by a wide margin.

These numbers assume you are optimizing your configuration. An untuned Lambda with 1GB of memory and 500ms average execution will cost 5x more than the estimates above. An over-provisioned Kubernetes cluster with idle nodes will cost 3x more. The cheapest infrastructure is the one your team understands well enough to right-size.

Server room hardware infrastructure for cloud container orchestration

Runtime Limitations and Data Locality

Every runtime model has constraints that will only become painful after you have committed to it. Knowing these upfront saves you from a costly migration later.

Edge Function Constraints

Edge runtimes use V8 isolates, not full Node.js. This means no `fs` module, no `child_process`, no native addons compiled with node-gyp. Popular packages like Sharp (image processing), Prisma (with certain database drivers), and anything that shells out to a CLI tool will not work. Cloudflare has been adding Node.js compatibility shims, but the coverage is incomplete and behavior sometimes differs from standard Node.js in subtle ways.

Request and response body sizes are limited. Cloudflare Workers cap at 100MB on the paid plan. Vercel Edge Functions limit responses to 4MB. If you are building an API that returns large JSON payloads or streams large files, edge functions are not the right layer for the actual data transfer, though they work well as a routing or authentication layer in front of a regional origin.

Execution time limits matter for anything beyond simple request/response cycles. Workers get 30 seconds of wall-clock time on the paid plan, but only a fraction of that can be CPU time. If your function does significant JSON parsing, data transformation, or cryptographic operations, you may hit the CPU limit well before the wall-clock limit.

Serverless Constraints

Lambda's 15-minute execution limit is generous for most API workloads but insufficient for batch processing, video transcoding, or training ML models. The 10GB memory ceiling is fine for APIs but restrictive for data-intensive workloads. Deployment package size (50MB zipped, 250MB unzipped) limits the libraries you can bundle, though Lambda container image support raises this to 10GB.

The biggest hidden constraint is concurrency. Lambda defaults to 1,000 concurrent executions per region, shared across all functions in your account. A traffic spike to one function can throttle all your other functions. You can request increases, but AWS reviews these manually and may not approve your request quickly during an incident.

Container Constraints

Containers have the fewest runtime restrictions, but they introduce operational complexity. You own the base image, which means you own security patching. A vulnerability in your Node.js base image or a transitive dependency in your OS packages is your responsibility to detect and fix. Container registries, image scanning, and automated rebuild pipelines add overhead that serverless teams never deal with.

Scaling containers to zero (as Cloud Run does) reintroduces cold starts. Keeping minimum instances running eliminates cold starts but means you are paying for idle capacity. Kubernetes adds complexity around pod scheduling, resource quotas, horizontal pod autoscalers, and cluster upgrades. For startups weighing these tradeoffs, our comparison of serverless containers vs Kubernetes goes deeper.

Data Locality: The Hidden Latency Tax

Running code close to users only helps if the data is also close. A Cloudflare Worker that queries a Postgres database 10,000 km away adds 100 to 200ms of network latency per query. Multiply that by three or four queries per request and your edge advantage evaporates.

Solutions are emerging. Turso replicates SQLite databases to edge locations with single-digit millisecond read latency. PlanetScale offers global read replicas for MySQL. Cloudflare D1 puts SQLite on the same network as Workers. DynamoDB Global Tables replicate across regions with eventual consistency. Each comes with tradeoffs: write latency (writes still go to a primary), consistency guarantees (most use eventual consistency for reads), and cost (replication is not free).

For most startups, the pragmatic answer is to run your API in a single region close to your primary user base and selectively push latency-sensitive logic (auth, feature flags, geo-routing) to the edge. Full edge-native architectures are viable but require rethinking your entire data layer.

Use Case Decision Framework

Choosing the right runtime is not about picking the "best" technology. It is about matching runtime characteristics to workload requirements. Here is a practical framework organized by use case.

API Routes for a Web or Mobile App

If your API is straightforward CRUD backed by a database, serverless functions (Lambda or Cloud Functions) in the same region as your database deliver the best balance of simplicity, cost, and performance. If you are using Next.js and Vercel, edge functions for lightweight API routes (auth checks, redirects, feature flags) combined with serverless functions for database-heavy routes is the optimal hybrid approach.

If your API handles over 50M requests per month, evaluate Cloud Run or a small Kubernetes deployment. The per-request savings at that volume justify the additional operational overhead.

Server-Side Rendering (SSR)

Edge functions are ideal for SSR when your pages do not require heavy database queries. Rendering a marketing page with personalized content at the edge delivers sub-100ms time-to-first-byte globally. For SSR that requires multiple database queries (dashboards, e-commerce product pages with inventory data), run SSR in the same region as your database using serverless or containers. The network round trip to the database dominates total response time, so edge execution provides minimal benefit.

Background Jobs and Queue Processing

Serverless functions are the default choice here. Lambda triggered by SQS, Cloud Functions triggered by Pub/Sub. The scale-to-zero model means you pay nothing when the queue is empty and scale automatically during spikes. For jobs that exceed the 15-minute Lambda limit (video processing, large data exports, ETL pipelines), use containers on Cloud Run jobs, AWS Batch, or a dedicated Kubernetes job runner.

ML Inference

Containers win decisively. ML models need to be loaded into memory (often 500MB to 4GB), and cold-loading on every invocation is prohibitively slow and expensive. A container running on Cloud Run with a minimum instance count, or a Kubernetes deployment with GPU-attached nodes, keeps the model warm and serves predictions in 10 to 50ms. AWS offers Lambda with 10GB memory and container image support, which works for smaller models, but the cold start penalty (5 to 15 seconds for a large model) makes it impractical for real-time inference.

Real-Time and WebSocket Workloads

Containers or Cloudflare Durable Objects. Standard serverless functions cannot maintain persistent connections. Durable Objects provide stateful, long-lived edge compute that can handle WebSocket connections, but they require designing around Cloudflare's programming model. For most teams, a container running a WebSocket server (Node.js with Socket.io, or a Go service) on Cloud Run or Kubernetes is simpler and more flexible.

Static Sites and JAMstack

None of the above. Use a CDN (Cloudflare Pages, Vercel, Netlify) for static assets and add edge or serverless functions only for dynamic API routes. Do not over-engineer your hosting. A static site behind a CDN with a few serverless functions is the simplest, cheapest, and fastest architecture for content-driven applications.

Picking the Right Model for Your Startup

After working with dozens of startups on their infrastructure decisions, here is the honest advice: start with the simplest model that meets your requirements, and migrate only when you hit a concrete limitation.

If you are a team of two to five engineers building a SaaS product, start with serverless. Use Vercel for your Next.js frontend with edge middleware for auth and feature flags. Use Lambda or Cloud Functions for your API. Use a managed database (PlanetScale, Supabase, Neon). Do not touch Kubernetes. Do not build a custom container orchestration pipeline. Ship product.

If you are a team of five to fifteen engineers with traffic above 20M requests per month, evaluate Cloud Run. It gives you the flexibility of containers with the operational simplicity of serverless. You can migrate incrementally, moving one service at a time from Lambda to Cloud Run, and compare costs and performance directly.

If you are a team of fifteen or more engineers running multiple services with complex inter-service communication, service mesh requirements, or GPU workloads, Kubernetes becomes justified. The operational overhead is real, but it is amortized across a larger team, and the cost savings at scale are significant.

The Hybrid Approach

Most production architectures in 2026 use more than one runtime model. A typical setup looks like this:

  • Edge functions for authentication, rate limiting, A/B tests, and geo-routing.
  • Serverless functions for API routes, webhook handlers, and event-driven background jobs.
  • Containers for ML inference, WebSocket servers, long-running workers, and high-traffic services where per-request pricing becomes expensive.

This is not over-engineering. It is matching each workload to the runtime that optimizes for its specific constraints. The key is having clear criteria for when a workload should move from one tier to another, and investing in CI/CD pipelines that make deployment to any target equally easy.

The wrong choice is the one you make based on hype or resume-driven development. Kubernetes is a great technology, but it is a terrible choice for a three-person startup. Edge functions are blazing fast, but they are the wrong place to run your database queries. Serverless is beautifully simple, but it will drain your budget at 500M requests per month.

Pick the boring option that fits your current scale. Build clear migration paths for when you outgrow it. And spend your engineering time on the product your customers actually pay for, not on infrastructure that only your ops team sees.

If you are unsure which runtime model fits your workload, we can help you evaluate the options and design an architecture that scales with your business. Book a free strategy call and let us map out the right infrastructure for your stage and traffic patterns.

Need help building this?

Our team has launched 50+ products for startups and ambitious brands. Let's talk about your project.

edge functions vs serverless vs containersserverless vs containers 2026Cloudflare Workers vs Lambdacloud deployment comparisonstartup infrastructure guide

Ready to build your product?

Book a free 15-minute strategy call. No pitch, just clarity on your next steps.

Get Started