Scale-to-Zero Without Containers

Scale-to-Zero Without Containers

Tako-kun ·

Scale-to-zero is usually a cloud or container thing. Google Cloud Run, AWS Lambda, Fly.io Machines — they all do it by pausing or destroying containers. If you’re running apps on your own servers with native processes, you’re expected to keep them running 24/7.

Tako does it differently. Your app scales to zero and cold-starts on demand, with no containers involved.

How it works

Every Tako app starts with desired instances set to 0 — on-demand mode. Here’s the lifecycle:

Diagram

Deploy. When you run tako deploy, the server starts one warm instance immediately — so your app is reachable right away. If that instance fails to start, the deploy fails. No surprise cold starts after shipping.

Serve. Requests route to healthy instances through Tako’s Pingora-based proxy. Each instance tracks in-flight requests and the timestamp of its last request.

Idle. An idle monitor checks instances periodically. If an instance has no in-flight requests and has been idle longer than idle_timeout (default: 5 minutes), it gets stopped. The app drops to zero running instances.

Cold start. The next request triggers a cold start. The proxy spawns a new process, waits for the app’s readiness signal (TAKO:READY:<port> via the SDK), and routes the request once the instance is healthy. For lightweight APIs, that first response is often only tens of milliseconds slower. Heavier apps can take longer.

What happens to requests during cold start

This is the tricky part. What if 50 requests arrive while the app is booting?

Tako uses a leader/waiter pattern. The first request becomes the “leader” and triggers the instance spawn. Every subsequent request becomes a “waiter” and queues behind it. Up to 1000 requests can queue per app. When the instance is ready, all waiters are unblocked simultaneously.

ScenarioResponse
Instance starts in timeNormal response (after cold start delay)
Startup exceeds 30s504 App startup timed out
Process crashes on start502 App failed to start
Queue exceeds 1000 requests503 App startup queue is full (with Retry-After: 1)

Instances are never killed while serving in-flight requests. The idle monitor only stops instances that are both idle and have zero active connections.

Why this matters for cost

If you’re running one app per server, scale-to-zero doesn’t save much. But most people don’t run one app per server.

A typical Tako setup might have a production API (always-on), plus a staging environment, an admin dashboard, a webhook processor, and a docs site — all on the same box. Without scale-to-zero, each of those keeps processes running around the clock. A Node.js process idles at 50-100MB. Five idle apps? That’s 250-500MB of RAM doing nothing.

With Tako’s on-demand model, those low-traffic apps consume zero resources when idle. The staging environment that nobody touches on weekends? Gone. The admin panel your team uses twice a day? Boots in 200ms when someone opens it.

This is especially useful on VPS instances where RAM is the constraint. A $6/month box with 1GB of RAM can comfortably host a handful of apps when most of them aren’t loaded into memory at the same time.

Configuration

Scale-to-zero is the default. You don’t need to configure anything for it to work. But you can tune it:

# tako.toml
[envs.production]
idle_timeout = 300  # seconds (default: 5 minutes)

[envs.staging]
idle_timeout = 60   # aggressive timeout for staging

For always-on apps, use tako scale to set a minimum instance count:

tako scale 2 --env production  # always keep 2 instances running

This persists across deploys, rollbacks, and server restarts.

Not serverless

This isn’t serverless. There’s no per-request billing, no function isolation, no event-driven invocation model. Your app is a normal long-running process — it just doesn’t run when nobody’s using it.

The cold start is a real process spawn, not a container unpause or a microVM boot. That’s why it’s fast: no image layers to unpack, no filesystem to mount, no network namespace to create. Just fork, exec, wait for readiness.

And because Tako’s proxy handles the queuing transparently, your app doesn’t need to know it was cold-started. No special warming logic, no readiness hacks. The SDK’s status endpoint is enough.

Try it

Every Tako app gets scale-to-zero out of the box. Deploy anything and watch it idle down after 5 minutes of quiet:

tako deploy
tako status  # see instance count drop to 0
# visit your app — it cold-starts on the first request

Check the deployment docs for the full setup, or how Tako works for the architecture behind on-demand scaling.