The Open Source AWS Lambda Alternative for HTTP APIs on a VPS

The Open Source AWS Lambda Alternative for HTTP APIs on a VPS

Tako-kun ·

AWS Lambda is the default answer when someone says “serverless function.” It made tiny deployable handlers feel normal, scales without you planning capacity first, and plugs into the rest of AWS like it was born there.

For event glue, cron fan-out, S3 triggers, and bursty workloads inside AWS, Lambda is excellent. This post is about a narrower question: what if your workload is mostly an HTTP API, and what you really want is the Lambda-shaped developer experience without renting the runtime one invocation at a time?

That is the shape Tako is built for: a fetch handler, a VPS, a proxy, TLS, deploys, logs, secrets, and optional scale-to-zero in one small platform.

Same small handler, different contract

Lambda gives you a handler. For HTTP traffic, you usually put API Gateway or a Lambda function URL in front of it. Lambda receives the HTTP request, maps it into an event payload, runs your function, and maps the return value back into an HTTP response.

Tako starts from the web API directly:

export default function fetch(request: Request): Response {
  return new Response("Hello from a VPS");
}

That is a complete Tako app. The interface is the same fetch handler pattern used by modern runtimes and frameworks: Request in, Response out. On Bun, the SDK hosts it directly. On Node, the tako.sh SDK bridges Node’s HTTP server to the same fetch shape. For Go, tako.ListenAndServe() wraps any http.Handler.

The difference is where the handler lives. Lambda runs inside AWS’s managed execution environment. Tako runs as a normal OS process on your server, behind Tako’s Pingora proxy.

ConcernAWS Lambda HTTP APITako on a VPS
HTTP entryFunction URL or API GatewayRoute in tako.toml
App shapeFunction handler receiving an eventWeb-standard fetch handler or Go http.Handler
RuntimeAWS managed runtime environmentNative Bun, Node, or Go process
Billing unitRequests plus duration and configured memoryThe VPS bill you already chose
StateInvocation model; use external services for durable stateNormal process plus TAKO_DATA_DIR for app-owned files
Scale-to-zeroBuilt into the Lambda modelOpt in with tako scale 0
DeploymentZip/image plus AWS config/IaCBuild locally, upload artifact, rolling update via tako deploy

This is not “Lambda is bad.” Lambda is very good at being Lambda. The trade is different: managed event compute versus owned-process HTTP hosting.

Where Lambda shines

Lambda is strongest when the function is a piece of an AWS-native event graph.

S3 object created? Invoke a function. EventBridge schedule fired? Invoke a function. SNS message arrived? Invoke a function. You do not want to think about a process, a port, a server, a service file, or a deploy target. You want a unit of compute that appears when an event arrives and disappears when the work is done.

That model also makes sense when traffic is highly spiky. If an API gets ten requests in the morning and ten thousand at lunch, Lambda’s concurrency model is the whole point. You can add provisioned concurrency, reserved concurrency, API Gateway throttling, IAM auth, CloudWatch alarms, X-Ray tracing, and all the other pieces around it.

The cost model is part of that bargain. AWS’s own Lambda pricing page describes the default model as request charges plus duration charges, where duration pricing depends on the memory configured for the function. For many small APIs, that bill can be tiny. For workloads already deep in AWS, keeping the compute next to DynamoDB, SQS, EventBridge, or S3 can be the cleanest architecture.

Tako is not trying to replace that whole universe. If your app is mostly AWS events, stay close to the events.

Where HTTP APIs get awkward

HTTP APIs are different. They often start as a simple request/response server and slowly collect normal server-shaped needs:

NeedWhat tends to happen on LambdaWhat happens on Tako
Web frameworkAdapt the framework into Lambda eventsRun the framework’s server output as an app
Persistent connectionsReach for API Gateway WebSockets or another serviceUse built-in durable channels for WebSocket/SSE
Background jobsAdd SQS, EventBridge, Step Functions, or another workflow toolUse built-in workflows
Local filesUse /tmp for scratch, external storage for durable dataWrite durable app files under TAKO_DATA_DIR
Long workSplit around Lambda’s invocation model and service quotasRun normal processes and move background work to workflows
Predictable spendModel requests, duration, memory, gateway, and add-onsPick a server size and watch the box

The first few functions feel wonderfully small. The tenth route often starts to look like a web server that has been chopped into pieces.

Tako goes the other direction. Your API is one app. It can still be tiny:

name = "api"
runtime = "bun"

[envs.production]
route = "api.example.com"
servers = ["ams"]
idle_timeout = 300

Deploy it:

tako init
tako deploy

Tako builds locally, uploads a compressed artifact over SFTP, runs production install on the server, starts a new instance, waits for readiness, moves traffic, and drains the old one. The deployment docs cover the full flow, but the important part is the shape: your app remains an app.

Scale-to-zero without becoming a function

One reason developers reach for Lambda is scale-to-zero. Paying nothing while idle feels right for side projects, staging APIs, admin tools, webhook receivers, and low-traffic internal services.

Tako has that too, but it is process-based. By default, new deploys keep one desired instance running so the first request after deploy is hot. If you want on-demand mode, set the desired instance count to zero:

tako scale 0 --env production

After the app is idle for its idle_timeout, Tako stops the process. The next request wakes it. While the cold start is in progress, the proxy queues waiters behind the first request, then releases them once the app is ready. The deeper version is in Scale-to-Zero Without Containers.

Diagram

This is not the same isolation model as Lambda. Tako does not create a fresh sandbox per invocation, and it does not pretend your server disappeared. It gives you the cost and RAM benefits of stopping idle apps while keeping the mental model of a normal service.

The VPS version of serverless

The phrase “serverless” never meant servers disappeared. It meant the platform took responsibility for them.

Tako takes responsibility for a smaller, more inspectable platform: the one running on your VPS. It manages routing, HTTPS, deploys, process lifecycle, logs, secrets, static assets, scale-to-zero, durable channels, and workflows. It is open source on GitHub, and you still own the machine. You can SSH into it. You can run SQLite. You can use native packages. You can put Cloudflare in front if you want a global network edge, or keep it boring with one region and one box.

That makes Tako a good Lambda alternative when:

Choose Lambda when…Choose Tako when…
Your app is mostly AWS event handlersYour app is mostly an HTTP API
You want AWS to own the full execution environmentYou want to own the server and process
Per-invocation metering matches the workloadA flat VPS bill is easier to reason about
You need deep AWS service integrationsYou need full Bun, Node, or Go runtime behavior
You are composing many cloud servicesYou want fewer moving parts on one box

The simplest summary is this: Lambda is managed event compute. Tako is owned HTTP infrastructure.

If your API wants to be a function, Lambda is a great place to run it. If your API wants to be a real server but you still want the small-handler DX, Tako gives you that shape on hardware you control.