The Best AWS Lambda Alternatives in 2026
Lambda is one of the most consequential pieces of infrastructure ever shipped, and for a huge class of workloads — event glue, S3 triggers, low-volume APIs, cron jobs — it's still the correct answer. Nobody switches away because the per-invocation price is too high. They switch because their workload grew a shape Lambda's execution model doesn't fit, and they usually discover it in production.
I'm Ajay, I build PandaStack, so this is a vendor's roundup — numbers only for my own platform, everyone else described qualitatively from public docs. The useful framing here isn't a ranked list; it's matching the specific constraint that broke to the option that resolves it, because 'alternatives to Lambda' covers at least four genuinely different products.
The five reasons people actually leave
- Cold starts you can't engineer away — a JVM or a Python function with a heavy import tree pays seconds on a cold invoke. Provisioned concurrency fixes it by paying for idle capacity, which undoes the reason you chose Lambda.
- The execution ceiling — the 15-minute maximum is a hard wall. Video transcoding, large data jobs, and long agent loops don't fit, and the workarounds (chunk, checkpoint, step-function it) turn a simple job into a distributed system.
- State that had nowhere to live — connection pools, warm caches, loaded models. Every workaround (RDS Proxy, an external cache, a sidecar) is another component you didn't want.
- VPC and data-locality latency — putting a function in a VPC to reach a private database used to be brutal and is now merely a design constraint you have to think about carefully.
- It was never stateless — the honest one. WebSockets, background work after the response, long-running sessions. These get bolted on until the architecture is mostly bolts.
The field, by what it actually replaces
Cloudflare Workers — if the problem is cold starts
Workers run on V8 isolates rather than per-request containers, which effectively removes cold start as a category of problem, and they run at the edge by default. The trade-off is real: it's a JavaScript-first runtime with a constrained execution environment and CPU-time limits per request, so it's a poor destination for a Python data job or anything with native dependencies. If your Lambda is a thin, latency-sensitive HTTP handler, this is the strongest option on the list.
Google Cloud Run — if the problem is the 15-minute ceiling
Cloud Run gives you a container with a much longer request timeout, real background processing if you configure CPU allocation correctly, and scale-to-zero. It's the most natural step up from Lambda for teams that want to keep serverless economics while escaping the function-shaped constraints. Cost: you need a container image, and you're now reasoning about concurrency-per-instance rather than one-request-per-invocation.
Vercel and Netlify Functions — if the problem is the developer experience
If your functions exist mainly to serve a frontend, colocating them with the frontend deploy removes an entire category of glue. These are largely Lambda underneath (or an edge runtime), so they inherit the same fundamental constraints — you're buying ergonomics, not a different execution model. Worth being clear-eyed about that.
Modal — if the problem is GPUs and Python
For ML inference and batch Python, Modal's decorator model and GPU provisioning target exactly the workload Lambda handles worst. It replaces the compute, not the event plumbing, so you'll typically still have something upstream doing the triggering. Not a general-purpose Lambda substitute; an excellent one for the specific case.
A long-running server — if the function was never stateless
The most underrated option. A single boring process on a small VM handles connection pooling, in-memory caching, WebSockets, and background work with no architecture at all — because those are the things a process does. Teams who moved a sprawl of eleven functions back into one service usually describe it as a relief. The trade is that you now pay for a process whether or not it's serving traffic, which is precisely what scale-to-zero platforms exist to fix.
PandaStack — if the problem is isolation, runtime, or long jobs
Ours sits at an angle to the rest: a function or a job runs in its own Firecracker microVM rather than a shared-kernel sandbox. That matters when the code being executed is untrusted — user submissions, LLM-generated code, per-tenant plugins — because the boundary is a hypervisor rather than a syscall filter. There's no 15-minute ceiling, and creates restore from a baked snapshot in about 179ms p50 (203ms p99), so per-invocation isolation stays affordable. Cron schedules use standard five-field expressions, and long-running jobs are just sandboxes that stay alive.
import os
from pandastack import Client
ps = Client()
# Deploy a function (a file or a directory bundle), then attach a cron
# schedule. Standard 5-field cron -- no vendor-specific rate() syntax.
fn = ps.functions.deploy(
name="nightly-rollup",
runtime="python",
path="./jobs/rollup", # bundled and stored, then run per invoke
entrypoint="handler.py",
env={"DATABASE_URL": os.environ["DATABASE_URL"]},
)
ps.schedules.create(
name="nightly-rollup-0200",
function_id=fn["id"],
cron="0 2 * * *",
)
# Each run executes in a fresh microVM. No warm-instance reuse to reason
# about, and no 15-minute wall to design around.Do this before you migrate anything
Most Lambda migrations I've seen go wrong in the same way: the team moves everything, when two functions were the problem and forty were fine. Lambda is excellent at what it's good at, and a half-migrated estate is worse than either endpoint.
- Measure which functions actually hurt. Pull duration percentiles and cold-start counts per function. Usually a handful dominate the pain and the bill.
- Classify each one: thin HTTP handler, long batch job, stateful session, or event glue. Each class has a different best destination, and event glue should usually just stay on Lambda.
- Check what's really causing the latency. A 3-second P99 is often a database round-trip inside a VPC, not the cold start — moving platforms won't fix that, and you'll have migrated for nothing.
- Move one function, keep the trigger. Run it in parallel with the Lambda for a week and compare real numbers before touching the rest.
- Only then decide whether the remaining functions want a platform or want to be consolidated into one long-running service.
The summary
Match the destination to the constraint: cold starts point at isolate runtimes, the 15-minute ceiling points at containers or VMs, statefulness points at a long-running server, GPUs point at ML-specific platforms, and untrusted code points at hardware isolation. And keep the functions that are working where they are — the goal is to fix the workloads Lambda's model doesn't fit, not to win an argument about serverless.
Frequently asked questions
Is there a way to eliminate Lambda cold starts without provisioned concurrency?
Not entirely, though you can shrink them a lot: trim the deployment package, lazy-import heavy dependencies inside the handler instead of at module scope, prefer lighter runtimes, and use SnapStart where your runtime supports it. Provisioned concurrency does solve it, at the cost of paying for idle capacity — which is often still cheaper than migrating, so price that honestly before you move. If cold start is genuinely the blocking constraint, an isolate-based runtime removes the category rather than mitigating it.
What should I use for jobs longer than 15 minutes?
The common paths are a container platform with a long request timeout (Cloud Run), a batch service (AWS Batch, ECS tasks), or a microVM sandbox that simply stays alive until the job finishes. Step Functions plus chunked Lambdas also works and is the most AWS-native answer, but it turns one job into a distributed workflow with checkpointing you now maintain — worth it for genuinely long pipelines, overkill for a 40-minute transcode.
Is running untrusted code on Lambda safe?
Lambda's own isolation is strong — it runs on Firecracker microVMs underneath, which is a hardware-virtualization boundary. The practical problems are the constraints rather than the boundary: the 15-minute ceiling, limited control over the execution environment, and the fact that the function's IAM role and network position are inherited by whatever code you run. If you're executing user-submitted or model-generated code, you want per-execution isolation plus egress control and a fresh filesystem each time, which is easier to express on a platform designed for it than on Lambda.
Should I move Lambda functions back into a single service?
Frequently, yes — particularly when several functions share a database, a cache, or the same deployment cadence, and when your operational overhead is dominated by the glue between them rather than the compute. A single long-running service gives you connection pooling, in-process caching, and ordinary debugging for free. The reason not to is genuinely spiky traffic where paying for an idle process is worse than paying per invocation, which is exactly the gap that scale-to-zero app platforms close.
Keep reading
49ms p50 cold start. Fork, snapshot, and scale to zero.