The hard question on Vercel is rarely “can I run this.” It is which box the work belongs in. On 15 October 2026, the company published a Knowledge Base guide that sorts the answer by a single fork: does an incoming request start the work, or does a process stay up and pull it. The same Ship SF day added Daemons to that list for the second case.

Work starts with a request or a pull loop

Functions still cover the request path. API routes, webhooks, and server-rendered pages run when traffic arrives. Vercel scales them with demand. Duration limits still bound each invocation. For work that should continue after the response, waitUntil() or Next.js after() can finish inside that same limit; unfinished tasks die if the Function times out.

Container images sit on the same request path when the handler needs a custom runtime or system library. A Java API, a PHP app, or a service that depends on FFmpeg packages the runtime in a Dockerfile. Vercel still runs that image as a Function on Fluid compute. Capacity scales with HTTP. You maintain the image; the platform keeps the request lifecycle.

Daemons are the new third option for work that never waits on an inbound call. You deploy a container image, set how many instances each region should keep, and the process stays running so it can pull from a queue, a workflow engine, a database, or another API. There is no inbound HTTP or TCP. Continuity is the point. The KB’s short version is that a container image changes what a Function runs, while a Daemon changes how a worker runs.

Daemons join the menu after Ship SF

Until this week, teams could already put custom runtimes next to Next.js through containerized Functions, and they could push background work through Queues, Workflows, and Cron Jobs. What the menu lacked was a first-class continuous pull worker. The 15 October changelog puts Daemons in public beta for Celery, BullMQ, RabbitMQ, Kafka consumers, Temporal and Cadence workers, and self-hosted CI runners that poll for jobs. The backends blog pairs that launch with Python GA and broader container support. Ship’s San Francisco stop, at the Palace of Fine Arts, is where CTO Malte Ubl introduced the primitive on stage.

So the guide is doing product work as much as documentation work. It teaches the old two options carefully, then slots Daemons beside them instead of treating the beta as a standalone SKU announcement.

Three primitives share Fluid compute under different contracts

All three run on Fluid compute. The contracts diverge from there. Functions (source or container) autoscale with requests and stay inside Function limits. Daemons take a fixed instance map per region. Vercel restarts crashes and does not autoscale during the beta. Dashboard scaling overrides stick across deploys until you clear them.

Daemons are available on Hobby, Pro, and Enterprise inside plan quotas. Hobby meters Active CPU, so a long-poll idle worker burns less allowance than a busy loop. Only production deployments start them. Preview deployments skip Daemons. vercel dev warns and leaves them out; local runs use Docker. Memory per instance is 1 to 8 GiB, default 2 GiB. Default shutdown is SIGTERM plus ten seconds, configurable up to an hour. Maturity reads usable for teams that already operate pull workers and can own capacity; production-shaped only after shutdown and idempotency are proved on your queue.

Stripe webhooks, Temporal workers, and nightly imports land differently

The KB’s workload examples are the Monday map. A Stripe webhook stays on a Function. If fulfilment needs retries of its own, publish to Vercel Queues and consume with a push Function, or keep an existing poll worker on a Daemon. An existing .NET HTTP API with a tested Dockerfile becomes a containerized Function, still request-scaled. An existing BullMQ or Temporal worker that long-polls its task queue becomes a Daemon. Month-end PDF reports that burst with traffic fit Queues plus a consumer Function, or Workflows when steps must pause and resume. Onboarding that waits days for human approval fits Workflows. A nightly catalog refresh fits Cron Jobs; continuous polling of the same supplier fits a Daemon.

One ecommerce app can mix them: Functions for payment webhooks, Queues for receipts, Workflows for fulfilment steps, a containerized Function for a Java inventory API, and a Daemon for the Temporal worker that was already in the repo.

Idle container Functions still die; Daemon capacity stays manual

The common mis-ship is packaging a polling loop as a container image and expecting it to stay warm as a Function. The KB is explicit: containerized Functions scale down when idle. Continuity requires the Daemon row.

Daemons hand capacity back to the operator. If the queue outruns your instance count, backlog grows until you redeploy or override scaling. During a production rollout, old and new instances briefly share the work source, so both versions must tolerate overlap. On stop, the process should refuse new work after SIGTERM and finish or release in-flight jobs safely. Acknowledge queue messages after success. Other beta edges include no persistent local disk, Linux amd64 only, and no Daemons yet when the project root is a monorepo subfolder. Independent cost benches against ECS or Cloud Run were not published with the launch.

Map the start trigger before you add a daemons block

List each background path in the app and mark whether a request starts it. Keep request work on Functions, with a container image only when the runtime demands it. Reach for Daemons when the process must stay up and pull. Start with one production consumer you already trust, watch Logs and queue lag, and treat autoscaling as a later GA question. The guide’s value is the menu; Daemons simply give continuous workers a seat at it.