Overview
A deployment is an additional named copy of an existing agent. Each deployment runs the same agent image as production under a different name. Use deployments to stage changes, test against real infrastructure, or share preview builds without affecting the version your users connect to.
Non-production deployments are a beta feature, available on the Ship plan or higher. The CLI surface, quotas, and behavior described here might change.
This page is about non-production deployments. To learn how to configure, deploy, and roll back agents in general, see Deployment management.
Every agent has a reserved deployment named production, which is created automatically. You can't create or delete a deployment named production, and it's the default target when you omit the --deployment flag. Non-production deployments are additional copies that you create, test, and delete as needed.
Deployment names
A deployment name must satisfy the following requirements.
- Start and end with an alphanumeric character.
- Contain only alphanumeric characters,
-,_, and.. - Be a maximum of 63 characters long.
If you omit the deployment name, commands target production. Invalid names are rejected with an error rather than being dispatched to production.
Deployments require the livekit-agents Python SDK 1.6 or later and an up-to-date LiveKit CLI. Earlier versions don't register the agent worker under its deployment, so dispatches that target a non-production deployment won't reach the agent.
When to use a deployment
Use a deployment when you want a copy of your agent with the following characteristics:
- The same image as production.
- Isolated from production traffic.
- Can be created and torn down without a production redeploy.
- Sleeps when idle and only costs compute while awake.
Common cases are a staging deployment that mirrors production for pre-release testing, or a short-lived dev deployment for a single change.
Lifecycle
Non-production deployments behave differently from the production deployment:
| Behavior | Production | Non-production deployment |
|---|---|---|
| Startup | Stays warm on paid plans | Always cold-booted |
| Idle | Stays running on paid plans | Sleeps |
| Incoming session while asleep | N/A | Wakes on demand |
| Redeploy | Drains in-flight sessions | Immediately disconnects active sessions |
| Rollback | Drains in-flight sessions | Not supported |
When a non-production deployment is idle, it scales to zero and sleeps. The next request for that deployment wakes it, which adds a short cold-start delay before the first session connects. On paid plans (Ship and Scale), production stays warm and doesn't scale to zero; on the Build (free) plan, production also scales to zero when idle. See Cold start for details.
There is no drain period when restarting or redeploying a non-production deployment. These actions immediately disconnect active sessions. Rollback isn't supported for non-production deployments — only production can be rolled back, and production redeploys and rollbacks drain normally, giving active sessions up to 1 hour to complete. Use non-production deployments only for traffic that can tolerate interruptions.
Billing
Compute is billed only while a deployment is awake. Sleeping deployments don't incur any costs. Deployment compute is included in the parent agent's compute usage.
Quotas
Each plan allows a fixed number of non-production deployments per agent. The production deployment doesn't count against this quota.
| Plan | Non-production deployments per agent |
|---|---|
| Build (free) | 0 |
| Ship | 2 |
| Scale | 5 |
| Enterprise | 5 (customizable) |
A deployment counts against the quota whether it's awake or sleeping. To free a deployment, delete it with lk agent delete --deployment <name>.
Branch on deployment name at runtime
LiveKit Cloud sets the LIVEKIT_AGENT_DEPLOYMENT environment variable on every agent's containers, regardless of which deployment it runs in. A non-production deployment sets it to the deployment name (for example, staging); the production deployment sets it to an empty string. You can read this variable at runtime to branch on the current deployment. For example, you can use it to select a deployment-specific secret.
Secrets are shared so each deployment of an agent has access to the same set of secret keys. To vary behavior or credentials per deployment, read the LIVEKIT_AGENT_DEPLOYMENT environment variable at runtime and branch based on its value.
A common pattern is to prefix secret keys by deployment (for example, STAGING_OPENAI_API_KEY, DEV_OPENAI_API_KEY) and selecting the appropriate key in code.
import osfrom livekit.agents import JobContextdef resolve_openai_key() -> str:# Empty string means production.deployment = os.environ.get("LIVEKIT_AGENT_DEPLOYMENT", "")if deployment == "staging":return os.environ["STAGING_OPENAI_API_KEY"]if deployment == "dev":return os.environ["DEV_OPENAI_API_KEY"]return os.environ["OPENAI_API_KEY"]async def entrypoint(ctx: JobContext):openai_key = resolve_openai_key()# ... configure your agent with openai_key
function resolveOpenAIKey(): string {// Empty string means production.const deployment = process.env.LIVEKIT_AGENT_DEPLOYMENT ?? '';if (deployment === 'staging') {return process.env.STAGING_OPENAI_API_KEY!;}if (deployment === 'dev') {return process.env.DEV_OPENAI_API_KEY!;}return process.env.OPENAI_API_KEY!;}const openaiKey = resolveOpenAIKey();// ... configure your agent with openaiKey
Isolated, per-deployment secrets are planned for a future release. Until then, use the shared secret prefix convention described in this section.
Walkthrough
This walkthrough creates an agent, deploys a staging copy, promotes it to production, then tears it down. It assumes you already have a working agent and are familiar with the LiveKit CLI.
Create the agent from your agent project directory. This also creates the reserved
productiondeployment:lk agent create .Deploy a
stagingcopy from the same working directory. This builds and pushes the image under thestagingdeployment:lk agent deploy --deployment stagingExercise the deployment by dispatching to it (see Dispatch to a deployment). The first request wakes the deployment from sleep.
When the change looks good, promote the
stagingimage to production with no rebuild:lk agent promote --deployment stagingDelete the
stagingdeployment to make room for another deployment. Omitting--deploymentwould delete the whole agent, so always pass the name:lk agent delete --deployment staging
lk agent delete without --deployment deletes the entire agent, including production. To remove only a non-production deployment, always pass --deployment <name>.
Dispatch to a deployment
Deployment is an optional field anywhere you specify an agent. Omit it to target production. For the full dispatch reference, see Agent dispatch.
For example, dispatch to a deployment from a token:
lk token create --join --open meet --agent steve-agent --deployment staging
The agent worker itself needs no code change to register under a deployment — the LiveKit CLI sets LIVEKIT_AGENT_DEPLOYMENT on the deployment's containers automatically.
Observability
In V1, only the production deployment emits metrics to Agent Observability. Per-deployment metrics are planned. To debug a non-production deployment, use logs:
lk agent logs --deployment staging --log-type deploy
Deployments are created and managed through the LiveKit CLI. In the dashboard, you can select a deployment when dispatching through the Agent Console and SIP dispatch rules.
Continuous integration
The livekit/deploy-action GitHub Action deploys to the production deployment. It doesn't accept a deployment name, so to deploy a non-production deployment from CI, run the LiveKit CLI directly with --deployment:
name: Deploy stagingon:pull_request:jobs:deploy:runs-on: ubuntu-latestenv:LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}steps:- uses: actions/checkout@v4- run: curl -sSL https://get.livekit.io/cli | bash- run: lk agent deploy --deployment staging
FAQ
Frequently asked questions about deployments and agents.
Does this affect the production agent?
No. Production keeps its own lifecycle, resources, and traffic. Creating, deploying, or deleting a non-production deployment never changes production.
Are secrets isolated between deployments?
No. All deployments of an agent share the same secrets. Use the LIVEKIT_AGENT_DEPLOYMENT environment variable to branch on the deployment name and use a prefix convention (for example STAGING_OPENAI_API_KEY) to vary credentials per deployment. Per-deployment secrets are planned for a future release.
What happens when a deployment is idle?
It sleeps (that is, scales to zero) and incurs no billing costs while sleeping. The next request wakes it on demand, resulting in a short cold-start delay before the first session connects.
Does redeploy drain in-flight sessions on a non-production deployment?
No. There is no drain period for non-production deployments, so restart and redeploy immediately disconnect active sessions. Rollback isn't supported for non-production deployments. The production deployment drains on redeploy and rollback as expected.
Can free-tier customers use deployments?
No. Deployments are available on the Ship plan or higher. The Build plan allows zero non-production deployments. To upgrade, see the pricing page for details.
Are there per-deployment secrets?
Per-deployment secrets are planned for a future release. In the meantime, you can use the shared-secret prefix convention to use different secrets for different deployments.
Where can I get help?
Ask questions and share what you're building in the LiveKit community forum . Direct email support from the LiveKit team is available to projects on the Ship plan or higher. To compare plans and the support each one includes, see the pricing page.