Deploy and go live

Two deployables, two targets: tasks go to Trigger.dev, the zone goes to Vercel. Neither knows about the other; the platform is what joins them.

1. Environments

Trigger.dev has three: Development, Staging, Production. Which one anything talks to is decided entirely by which secret key it holds — there is no environment name in your code, because tasks are triggered by their string id.

Development   tr_dev_…    trigger dev, running on your machine
Staging       tr_prod_…   deployed, for verification
Production    tr_prod_…   deployed, live

That has one consequence worth internalising: a platform runtime environment configured with a staging key can only reach tasks deployed to staging. If a run fails with "task not found" and the task id is definitely right, check which key the runtime environment holds.

It also means environment switching is a one-line change — swap the key.

Deployed runs cannot read your local files. trigger dev loads .env.local from the repository root, which is why the dev loop works with no extra setup. A deployed task has no filesystem of yours, so every variable it needs must be set in the Trigger.dev dashboard for that environment. Forgetting this produces a task that works perfectly in dev and throws on an undefined variable in staging.

Set these per Trigger.dev environment:

DATABASE_URL
CXPA_API_URL
CXPA_REVENUE_CHAT_AGENT_API_KEY
CXPA_REVENUE_CHAT_INGEST_API_KEY
CXPA_NIGHTLY_ETL_AGENT_API_KEY

Third-party credentials are not in this list, and should not be: they are resolved from the platform on every run.

2. Database migrations

Your own database, your own migrations. Apply them before deploying code that depends on them:

bash
npx supabase link --project-ref <ref>
npx supabase db push

3. Deploy the tasks

bash
npx trigger deploy --env staging

Verify in staging, then:

bash
npx trigger deploy --env prod

Check that additionalFiles in trigger.config.ts lists every non-code file a task reads at runtime. This is the failure that only ever appears in a deployed environment.

4. Deploy the zone

The zone is its own Vercel project, with root directory web.

Set the six environment variables from Register the zone, with production values and no trailing slashes. DISABLE_ZONE_AUTH must not be present at all.

Two Vercel settings must be changed, and both are non-obvious:

Skew Protection → off, on both the zone project and the platform project. With it on, the two projects' deployment identifiers collide during the asset proxy and every _next/* request ends in a redirect loop.

Deployment Protection → Vercel Authentication: Only Preview Deployments, or off. With "All Deployments", proxied asset requests get redirected to Vercel's SSO page and loop. Password protection likewise must be off or preview-only on production.

Neither weakens security: the zone rejects any request without a valid JWT at the middleware. Vercel-level protection on production adds nothing and breaks the proxy.

Deploy the zone in the same region as the platform project. Cross-region rewrites add 50–200 ms to every request.

5. Go-live checklist

Each item is marked with who can do it: [admin] platform administrator, [member] anyone in the org, [maintainer] whoever maintains the platform deployment, [you] your own infrastructure. If you hold none of the first three, this is your delegation list — see Roles and permissions.

Platform configuration:

  • [admin] Runtime environment holds a production secret key, and its connection test passes.
  • [admin] Nango environment configured, if any credential is OAuth.
  • [admin] Each agent's Task ID matches its deployed task's id exactly.
  • [admin] Max run duration is set to something realistic and agrees with the task's maxDuration.
  • [member] Every required credential requirement shows as connected.
  • [member] Schedules exist, with the right cron and the right timezone.
  • [member] An email action on failed exists for unattended agents.
  • [admin] External trigger and webhook switches are on only if something external needs them.

Zone:

  • [maintainer] Registry entry present, ZONE_*_URL set, platform redeployed without build cache.
  • [you] All six zone variables set; DISABLE_ZONE_AUTH absent.
  • [you] curl against the zone's own origin returns 401.
  • [you] Assets load from the platform's origin.
  • [you] Skew Protection off on both projects; Deployment Protection preview-only or off.

[admin] Now set each agent's status to Active at /acme/{agentSlug}/settings.

This has to happen before the end-to-end checks, not after. A discovery agent refuses to execute — Run Now returns Agent is not active (status: discovery) — so there is no way to prove the agent works while it is still in discovery. Discovery protects you while you are configuring; it is not a mode you can test in.

End-to-end, once active:

  • [member] Trigger each agent once via Run Now or the input surface. Both reach completed.
  • [member] Run detail shows the expected output_data and a non-zero outputs.
  • [member] Logs load for a completed run.
  • [member] Every credential resolved cleanly — no resolveCredential errors in the run logs.
  • [member] The zone loads, triggers a run, and shows progress through to a result.
  • Schedules are disabled until the manual checks pass, so a cron fire cannot land mid-verification.

These runs are real. The platform has no test mode: once an agent is active, every run counts toward its run history, and any run reporting outputs feeds the customer-facing value metrics. Verify with input that is safe to process, and expect the rehearsal to appear in the numbers.

6. After go-live

Rotating a key is a two-step change with a gap. Rotate on the platform, then update the consumer and redeploy. Between the two, calls with the old key fail — so do it deliberately, not during a busy period:

KeyConsumer to update
agent_api_keyThe Trigger.dev environment variable
ingest_api_keyWhatever external system triggers the agent
zone_jwt_secretThe zone's Vercel environment, then redeploy
Runtime secret keyThe platform runtime environment only — agents pick it up automatically

That last row is the payoff for using a shared runtime environment: rotating a Trigger.dev key is one edit, no matter how many agents use it.

Adding an agent to an existing org is much shorter than the first one: create the record, point it at the existing runtime environment, declare its credential requirements, deploy the task. No platform redeploy unless it needs a zone.

7. Onboarding another customer

Adding a customer is a different shape from adding an agent, and more expensive than most people expect. Worth knowing before you price the second one.

Everything scoped to an organization has to be created again, and — if that customer gets a zone — a zone deployment is per customer, not per product. The org and agent slugs are compiled into the zone's basePath at build time, so one build serves exactly one (org, agent) pair. There is no multi-tenant zone build.

Per customer:

StepWhoRepeat per customer?
Create the organizationPlatform adminYes
Runtime environment (Trigger.dev)Platform adminOnly if they use their own Trigger.dev project
Nango environmentPlatform adminYes — recommended, so connections stay separated
Agent recordsPlatform adminYes
Credential requirementsPlatform adminYes
Connect the credentialsThe customerYes
A separate zone deployment, built with their slugsYouYes, if they get a zone
Registry entry + ZONE_*_URLPlatform maintainerYes
Platform redeploy without build cachePlatform maintainerYes
Deploy the tasksYouNo — one deployment serves every customer

The task code is the one thing that does not multiply. Everything else does, and the last three rows are the ones that hurt: each new zoned customer needs a change to the platform's source and a redeploy, performed by someone who may not be on your team. Build that lead time into onboarding rather than discovering it on the day.

Two consequences worth designing for early:

  • Decide the database shape before customer two, not after. One database per zone deployment or one shared with an org predicate on every query — Zone data and tenancy sets out the fork, and retrofitting the org column later means auditing every query you have written.
  • A customer without a zone is far cheaper. If the built-in JSON editor and the run detail page are enough for a given customer, they need no deployment, no registry entry, and no platform redeploy.

8. There is no staging

Worth stating plainly, because the absence is easy to mistake for something you have not found yet.

The platform has no environment concept. Agents and organizations carry no environment flag; a runtime environment is a connection to a Trigger.dev project, not a platform-side environment; and discovery status means "cannot run at all", not "runs against staging".

So there is no supported way to rehearse an agent against anything other than production. What you can do instead:

  • Point a second agent record at a non-production runtime environment. Give it a runtime environment holding your Trigger.dev staging key and its own credential requirements connected to test accounts. It is a real agent in the customer's org — or in an org of your own — and it is the closest thing to a staging agent that exists.
  • Keep schedules disabled until the manual checks pass, so nothing fires while you are still verifying.
  • Expect your verification runs to count. Once an agent is active, every run appears in its history, and any run reporting outputs feeds the hours-saved and ROI figures the customer sees. There is no flag that excludes a test run. Rehearse in an org of your own where you can, and where you cannot, use input that is safe to process and accept the handful of runs in the numbers.

Next

Troubleshooting — worth reading before you need it.