helm install, default values, no external dependencies. Run the production install for real workloads: external Postgres, Redis, ClickHouse, and object storage, your own secrets, and HA on the datastores you already operate. Each configuration decision below belongs to one path or the other.
This guide alone is unlikely to produce a hardened production deployment - securing, scaling, and reliability-tuning your cluster remain yours to own. Should the burden get too much, we’d be happy to see you on Trigger.dev cloud where we deal with these concerns for you.
Architecture
The chart deploys a webapp, a supervisor, and the datastores they depend on. The supervisor pulls runs from the webapp and schedules each one onto a worker node, which executes the task in a container sized by its machine preset. Each component maps to a top-level key invalues.yaml: webapp, supervisor, postgres, redis, electric, clickhouse, s3 (object storage), s2, and registry. The datastores default to deploy: true and run in-cluster; set deploy: false with an external block to bring your own. The registry is the exception - it defaults to deploy: false, so you point it at an external one. Webapp settings live under webapp, supervisor settings under supervisor.config, and each service takes extraEnvVars for anything else.
Requirements
Prerequisites
- Kubernetes cluster 1.19+
- Helm 3.8+
- Kubectl with cluster access
Resources
The following are minimum requirements for running the entire stack on Kubernetes: Cluster resources:- 6+ vCPU total
- 12+ GB RAM total
- Persistent volume support
- Webapp: 1 vCPU, 2 GB RAM
- Supervisor: 1 vCPU, 1 GB RAM
- PostgreSQL: 1 vCPU, 2 GB RAM
- Redis: 0.5 vCPU, 1 GB RAM
- ClickHouse: 1 vCPU, 2 GB RAM
- Object Storage: 0.5 vCPU, 1 GB RAM
- Workers: Depending on concurrency and machine preset
resources section in your values.yaml. For example:
Evaluation install
Bundled datastores let you run the whole stack with a single command and no external services. The default values are insecure and are only suitable for testing - for real workloads, follow the production install instead.1
Install the chart with default values
2
Port-forward the webapp
http://localhost:3040.3
Log in with the magic link
Default installs print the login link to the webapp logs instead of sending email.Open the printed link to sign in.
Verify it
Confirm every component reached a healthy state:Running with all containers READY. Migrations and bootstrap run inside the webapp pod rather than as separate jobs, so if the webapp stays unready, check its logs. If a pod is stuck in Pending or CrashLoopBackOff, jump to Troubleshooting.
Once you can sign in and trigger a run, you’ve validated the stack. For a deployment that survives restarts, upgrades, and load, move on to the production install.
Production install
Running external datastores is the requirement that separates a production install from an evaluation one. You supply your own Postgres, Redis, ClickHouse, and object storage, manage secrets yourself, and point the chart at each service. The steps below layer onto the samehelm upgrade command, driven by a custom values file.
Secrets
Application, control-plane, and bundled-datastore secrets left unset are generated on first install and retained acrosshelm upgrade - they are never rotated automatically, so sessions, encrypted data, and datastore volumes survive upgrades. This auto-generation is the default and needs no configuration.
For production, supply your own Secret instead so credentials live outside the release. With secrets.existingSecret set, the chart generates nothing and reads every key from your Secret; a preflight check fails the install - before touching a running release - and lists any keys it can’t find.
To pin values inline instead of letting the chart generate them - for example to share MANAGED_WORKER_SECRET with an external supervisor - set them under secrets:
existingSecret. It must contain at least SESSION_SECRET, MAGIC_LINK_SECRET, ENCRYPTION_KEY, PROVIDER_SECRET, COORDINATOR_SECRET, and MANAGED_WORKER_SECRET - plus s3-auth-access-key-id and s3-auth-secret-access-key if you deploy the bundled MinIO with s3.auth.existingSecret cleared:
PROVIDER_SECRET and COORDINATOR_SECRET into the webapp deployment, and the pre-upgrade check requires both, so an existing Secret must include them. For a deployment that already runs, add them before upgrading:
ENCRYPTION_KEY: changing it makes existing encrypted data unreadable. If a deployment is still running a previously published default and cannot rotate yet, set ALLOW_INSECURE_DEFAULT_SECRETS=true on the webapp to keep booting while you plan a migration.
Custom values
Most values map directly to the environment variables documented in the webapp and supervisor environment variable overview. Environment variables useUPPER_SNAKE_CASE; Helm values use camelCase:
values-custom.yaml that overrides the defaults with your URLs and resource requests:
External services
Disable each built-in datastore and point the chart at your own. Every service supports direct configuration or an existing Kubernetes secret; use existing secrets to keep credentials out ofvalues.yaml and Helm releases.
PostgreSQL
Direct configuration:Redis
Direct configuration:ClickHouse
Migration from the old Bitnami subchart to the officialclickhouse/clickhouse-server image is automatic - a normal upgrade moves you across with no manual step. The one exception: if you pinned clickhouse.image to a Bitnami tag, switch it to an official clickhouse/clickhouse-server tag first, since Bitnami tags don’t exist in the official repository.
Trigger.dev requires ClickHouse 25.8 or newer. The bundled ClickHouse is single-node — run
ClickHouse externally for a clustered or replicated setup.
An inline external
username/password is percent-encoded into the connection URL for you, so
store the raw value - special characters like @ : / % are handled automatically.
(Credentials from existingSecret are injected at runtime and are unaffected.)Object storage
Object storage holds deploy artifacts and large payloads. See the Docker object storage setup for conceptual information. Disable the bundled MinIO and point at any S3-compatible endpoint. Direct configuration:PostgreSQL SSL with custom CA certificates
When connecting to PostgreSQL instances that require custom CA certificates (such as AWS RDS with SSL verification), mount the CA certificate as a volume and configure the webapp to use it:- No plaintext credentials in
values.yamlor Helm releases - Complete
DATABASE_URLstored securely in Kubernetes secrets - Compatible with secret management tools (External Secrets Operator, etc.)
- Follows Kubernetes security best practices
Registry setup
Built deploy images are pushed to a registry. See the Docker registry setup for conceptual information. Configure an external registry in yourvalues.yaml:
The internal registry (
registry.deploy: true) is experimental and requires proper TLS setup
and additional cluster configuration. Use an external registry for production.DNS performance
For production clusters we recommend deploying NodeLocal DNSCache. DNS queries — especially to managed Postgres or Redis endpoints — can be very slow under Kubernetes’ default resolver, and a node-local cache typically gives a large step change in latency and throughput across the cluster. The defaultndots: 5 setting also forces every cluster search domain to be tried before resolving hostnames with fewer dots (the case for most external database hosts). Lowering ndots to 1 on the webapp and supervisor pods avoids those extra round-trips.
Authentication
Authentication options are identical to the Docker-based installation. Configure the provider in yourvalues.yaml:
GitHub OAuth:
Worker token
The supervisor authenticates to the webapp with a worker token. The default bootstrap path generates one for you; supply your own token to manage workers separately. Bootstrap (default): the webapp generates a worker token and makes it available to the supervisor via a shared volume.1
Read the worker token from the webapp logs
2
Create a secret with the token
3
Point the supervisor at the secret
Operating your deployment
Upgrading
helm upgrade is safe to run as-is. Your generated secrets, data volumes, and the bundled ClickHouse are preserved and migrated automatically, so a normal upgrade needs no preparation. A few situations need one manual step first — expand any that apply to you.
You supply your own secret (secrets.existingSecret)
You supply your own secret (secrets.existingSecret)
With If a required key is missing, the upgrade stops before touching your running release and tells you which to add.
secrets.existingSecret set, the chart reads every key from your Secret and generates none, so any key the app needs must already be present there.As of chart 4.5.6 the webapp deployment references PROVIDER_SECRET and COORDINATOR_SECRET, and the pre-upgrade check requires both, so an existing Secret must carry them. Add both before upgrading:Something outside the chart reads a datastore password
Something outside the chart reads a datastore password
The bundled datastore passwords live in the The keys are
trigger-datastore Secret. If a maintenance job, a dashboard, or a secret sync reads one directly, point it there:clickhouse-admin-password, postgres-password, and minio-root-user / minio-root-password.You render manifests without cluster access (Argo CD, plain helm template)
You render manifests without cluster access (Argo CD, plain helm template)
During an upgrade the chart reads the cluster to keep your data and to check your Secret. Renderers that run offline can’t do that, so set these yourself:
- Point
clickhouse.persistence.existingClaimat your ClickHouse data volume (data-<release>-clickhouse-shard0-0) and keep it set on future syncs, so ClickHouse reuses its data instead of starting on an empty volume. - Confirm
PROVIDER_SECRETandCOORDINATOR_SECRETare already in your Secret before syncing.
Version locking
Trigger.dev 4.5.0 is the last version we officially support for running v3 (SDK v3) tasks. If
you still have v3 tasks, pin to exactly 4.5.0 or migrate to v4. 4.5.1 and
later reject v3 triggers and deploys with an upgrade message.
appVersion field determines the default image tags. Newer image tags may be incompatible with older chart versions and vice versa.
Troubleshooting
Check logs:- Magic links not working: Check webapp logs for email delivery errors
- Deploy fails: Verify registry access and authentication
- Pods stuck pending: Describe the pod and check the events
- Worker token issues: Check webapp and supervisor logs for errors
Task events
By default, task events (timeline, logs, spans) are stored in PostgreSQL. For production deployments we recommend storing them in ClickHouse instead, it scales to much higher volumes and avoids unbounded growth of theTaskEvent table.
ClickHouse is already deployed by the chart, so no extra services are required. To enable, set EVENT_REPOSITORY_DEFAULT_STORE on the webapp via extraEnvVars:
Realtime streams
Realtime streams power AI-agent token streaming and run streams. They default to v2, backed by the bundleds2 deployment — s2-lite, the open-source, self-hostable S2 server. The chart deploys it with a persistent volume, so no extra services are required.
To fall back to the Redis-backed v1 streams, set the default version to v1:
s2.deploy: false with no external endpoint. See helm show values for all s2 options.
CLI usage
See the Docker CLI usage section, the commands are identical regardless of deployment method.CI / GitHub Actions
When running the CLI in a CI environment, your login profiles won’t be available. Instead, use theTRIGGER_API_URL and TRIGGER_ACCESS_TOKEN environment variables to point at your self-hosted instance and authenticate.
For more detailed instructions, see the GitHub Actions guide.
Telemetry
By default, the Trigger.dev webapp sends telemetry data to our servers. This data is used to improve the product and is not shared with third parties. To disable telemetry, set in yourvalues.yaml:

