Skip to main content

Overview

ToolJet is an open-source, low-code platform for building internal tools: a visual app builder with 50+ datasource connectors, workflows, and the built-in ToolJet Database. This template deploys the ToolJet server — UI and API on port 3000, with PostgREST and a fallback Redis bundled inside the image — backed by a bundled PostgreSQL that holds both the application database and the ToolJet Database. The default is a single replica; tooljet.replicas scales out once the optional Redis is enabled.
This template deploys into an existing GVC that you already have — it does not create or manage a GVC.

What Gets Created

Your prerequisite secrets are not created by the template — see Prerequisites.

Prerequisites

Two dictionary secrets must exist before installing: the bundled database’s credentials, and ToolJet’s three root-of-trust keys. Their values never pass through Helm values.
1

Create the database credentials secret

The bundled PostgreSQL initializes with these and ToolJet connects with them (it creates its tooljet_db database alongside):
Set postgres.config.credentialsSecretName to this name. Keep the password URL-safe (letters, digits, -, _) — ToolJet places it in a connection URL as-is. PostgreSQL reads the secret only when its data directory is first initialized; see Rotating the Database Password for changing it later.
2

Create the key secret

Generate the three keys the same way ToolJet’s own setup scripts do, straight into the secret:
Set secrets.name to this name. Secrets are org-level, so no GVC flag is involved.
3

Back the keys up outside Control Plane

SECRET_KEY_BASE and LOCKBOX_MASTER_KEY are write-once: rotating LOCKBOX_MASTER_KEY makes every datasource credential ToolJet has stored undecryptable. Keep a copy of all three values somewhere safe.
Only if you turn Redis auth on, create one more dictionary secret with the key password and name it in redis.redis.auth.fromSecret.name (with redis.redis.auth.fromSecret.enabled: true). Redis, its Sentinel and ToolJet all read it:
Create the secrets before installing. Installing without one reports success, but the deployment then wedges silently — cpln logs returns nothing, and the only place the missing secret is named is status.versions[].message (also check RELEASE_NAME-postgres for the database secret and RELEASE_NAME-redis for the Redis secret):
The message reads The secret KEYS_SECRET_NAME no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. Creating the secret lets the deployment recover on its own; cpln workload force-redeployment RELEASE_NAME-tooljet --gvc GVC_NAME skips the wait.
Everything else works with the defaults. Two optional features need their own setup first:
  • Authenticated SMTP — a dictionary secret holding SMTP_USERNAME and SMTP_PASSWORD, and a decision made before installing, because ToolJet only picks up mail settings on its first boot. See Email.
  • Scheduled database backups — a bucket and cloud account for the bundled PostgreSQL. See Backing Up.

Installation

Once your key and database credentials secrets exist, install from the marketplace registry, pointing the chart at them:
Installing a second ToolJet release in the same org? Give it its own database credentials secret — secret names are org-wide. If you want email invitations, add the smtp.* values to this first install as well (see Email). Other ways to install and manage the template:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

ToolJet Server

Set tooljet.host only when you serve ToolJet on a custom domain; leave it empty and ToolJet derives its public URL from the workload’s canonical endpoint.
Do not lower tooljet.resources.maxMemory below the default 4Gi. The image bakes a 4096 MB Node heap, and the first boot’s schema migrations are killed for running out of memory at smaller limits (the container exits with code 137), leaving the workload in a crash loop that never finishes migrating.

Key Secret

The secret itself is created in Prerequisites; only its name is a value.

Email

SMTP powers user invitations and password resets. It is off by default, and a default install works without it — the first visitor still becomes Super Admin.
For an authenticated relay, create the credentials secret before installing and set smtp.auth.secretName to its name. The ToolJet identity is granted reveal on exactly that secret.
Configure SMTP at the initial install. ToolJet seeds its mail settings from the environment during a first-boot migration, so enabling smtp.* through a later helm upgrade has no effect — the values reach the workload, but ToolJet keeps mail disabled. Decide before you install.

Access

With publicAccess.enabled: false there is no public endpoint; external requests are refused and only workloads allowed by internalAccess reach ToolJet (plus your own machine through a tunnel — see Connecting).

Bundled PostgreSQL

One PostgreSQL instance backs the whole deployment, and ToolJet’s boot scripts create every database it needs using the credentials from that secret: The credentials secret seeds the database on first boot; editing it later does not change the database password (see Rotating the Database Password). Scheduled backups of this database are configured under Backing Up.
The ToolJet Database is a core part of ToolJet 3.x and cannot be turned off.

Bundled Redis

redis.enabled: true deploys the redis template and points ToolJet at it; it is required for more than one ToolJet replica (see Scaling and Availability). With redis.redis.auth.fromSecret.enabled: true Redis, Sentinel and ToolJet read the password from the prerequisite secret named by redis.redis.auth.fromSecret.name (see Prerequisites), which the ToolJet identity is granted reveal on.
Keep redis.redis.replicas and redis.sentinel.replicas at 1. ToolJet’s Redis client is not Sentinel-aware and connects straight to the service DNS name, so additional data nodes would spread writes onto read-only replicas. The chart refuses to render any other value.

Connecting

With publicAccess.enabled: false there is no public endpoint; reach the UI from your machine through a tunnel instead and open http://localhost:3000:

First Run

ToolJet ships no default account. The first person to open the endpoint completes the Super Admin onboarding and creates the initial workspace — and with the default publicAccess.enabled: true that form is reachable by anyone who finds the endpoint, so claim it as soon as the workload reports ready.
1

Wait for the ToolJet workload to report ready

The container waits for PostgreSQL, creates its databases, and runs all of its schema migrations before it starts serving. The first boot takes several minutes, and the very first pull of the multi-gigabyte image adds to that.
2

Open the endpoint and complete the Super Admin form

Browse to the canonical endpoint (or the port-forward URL) and fill in the Super Admin onboarding. That account owns the instance. Self-signup stays off until the Super Admin enables it.
3

Invite your team

Invitations are sent by email, so they only work if you configured SMTP at install time.

Operations

Backing Up

The bundled PostgreSQL is the postgres template, so its scheduled backup is available here under the postgres key — nothing extra to install. It is off by default. Enabling it adds the cron workload RELEASE_NAME-postgres-backup, which uploads a gzipped SQL dump of the whole instance (all three databases) to your bucket under the configured prefix.
Create the bucket, the Control Plane cloud account, and (for AWS) the bucket-scoped IAM policy before installing or upgrading with backups on. The per-provider steps, the IAM policy JSON, the GCS role, and the gcp / minio value blocks are on the postgres template page under Backup Prerequisites; use the same keys here, nested under postgres.backup.
The bundled database runs postgres:16, while the postgres template documents its backup feature for PostgreSQL 17 and later and ships a backup image built for the newer major. Scheduled backups have not been exercised against this template — rehearse a backup and a restore on a throwaway release before you rely on them, and check each object’s size: a near-empty gzip is a failed run, not a backup.
The dump does not cover your three keys — they live in the secret you created, so back that up separately. The PostgreSQL volume set RELEASE_NAME-pg-vs also takes a final volume set snapshot when the release is uninstalled, retained for 7 days.

Restoring a Backup

Each backup is a gzipped plain-SQL dump of the whole PostgreSQL instance. Restoring means replaying that SQL into the bundled PostgreSQL, following the restore procedure on the postgres template page against RELEASE_NAME-postgres.GVC_NAME.cpln.local with the credentials from your postgres.config.credentialsSecretName secret. From a client without network access to the GVC, the one transport that carries a dump into the container intact is cpln workload exec with --stdin and a base64 wrapper on both ends — raw binary piped through exec is corrupted:
Two constraints make this a planned operation: the dump contains CREATE ROLE and CREATE DATABASE statements, so a straight replay collides with the databases ToolJet already created and migrated on first boot; and no ToolJet replica may be connected while you drop and recreate those databases before the replay.
This restore path has not been exercised against this template end to end. Rehearse it on a throwaway release before you depend on it. Restoring from a volume set snapshot is likewise unverified here.

Upgrading from 1.0.0

Version 1.1.0 adopted the postgres 3.4.1 template, which stopped taking database credentials as values. postgres.config.username, .password and .database were removed: put the values your database was initialized with into the database credentials secret under Prerequisites (keys username, password, database), set postgres.config.credentialsSecretName to its name, and remove the three keys. The key secret is unchanged. Keep the same values so the running database still matches. A values file that still carries an old key fails the render with the postgres template’s message — config.username was REMOVED in postgres 3.4.0 — which tells you to create a dictionary secret; that is correct here too. Then continue with the sections below.

Upgrading from 1.1.0

Version 1.2.0 changes no values. The ToolJet container now starts through a chart-provided script that waits until PostgreSQL actually accepts connections before running the image’s own entrypoint, which removes a failed first attempt that earlier versions logged on a fresh install. Upgrade in place, then continue with Upgrading from 1.2.0.
The first helm upgrade after an install can restart the bundled PostgreSQL even when nothing about it changed, which interrupts ToolJet briefly; later upgrades of the same release do not.

Upgrading from 1.2.0

Version 1.3.0 removed postgres.credentials: the database credentials are now a prerequisite secret, the same one the postgres template requires on its own. Carrying the old key forward fails the render. 1.2.0 created the database secret itself (and a second copy, RELEASE_NAME-tooljet-db), so this upgrade deletes both. Before upgrading, create a secret under a new name holding the values your database was initialized with — not new ones, or ToolJet loses its database connection:
Then upgrade with postgres.config.credentialsSecretName set to that name and postgres.credentials removed. Your current values are in postgres.credentials of the 1.2.0 release, and also in the old secret named by its postgres.config.credentialsSecretName (cpln secret reveal SECRET_NAME -o yaml) until the upgrade deletes it. If you ran 1.2.0 with Redis auth on, redis.redis.auth.password was removed too (carrying it forward fails the render), and the chart-created RELEASE_NAME-redis-auth-password secret is deleted by the upgrade. Copy your current Redis password into a secret under a new name first:
Then also set redis.redis.auth.fromSecret.enabled: true and redis.redis.auth.fromSecret.name to the new name, and remove redis.redis.auth.password. With Redis auth off in 1.2.0 (the default), just remove redis.redis.auth.password from your values. The upgrade restarts the bundled PostgreSQL too (it now reads the new secret), so ToolJet briefly loses its database; it reconnects by itself. While access to the new secret propagates, the new version of a workload can wait in get-deployments reporting that it is not allowed to reveal the secret; the previous version keeps serving meanwhile, and it clears by itself.

Rotating the Database Password

Editing the secret alone does nothing to the database, and a running workload keeps the values it started with. Change one key and keep the others with export, edit, apply:
Run ALTER ROLE for the secret’s username in PostgreSQL first (URL-safe characters only), then update the secret, then right away force a redeployment of ToolJet, and wait until get-deployments shows a higher version number, alone and ready (right after the command the status may not show the restart yet, and ready: true alone can still describe the old replica). Do not redeploy the database: PostgreSQL reads the secret only when it is first initialized, so restarting it only adds downtime. Connections the app already has open keep working after ALTER ROLE; new ones fail until its redeploy finishes, so redeploy right away and rotate in a quiet window.

Rotating the Redis Password

Only with Redis auth on. Redis keeps no password on disk, but a running Sentinel holds the one it started with, so a new password is applied live in three places before ToolJet restarts. Each Redis node first accepts both passwords, which keeps replication and every connected client working throughout. rx and sx run a command on one Redis node or Sentinel (LOCATION is your GVC’s location; nodes and Sentinels are numbered from 0 up to redis.redis.replicas and redis.sentinel.replicas minus one):
ToolJet is briefly unavailable while it restarts (with tooljet.replicas of 2 or more it rolls one replica at a time). Redis and Sentinel need no restart: when they next start they read the new password from the secret.

Scaling and Availability

tooljet.replicas sets how many ToolJet replicas run. With more than one replica, all replicas must share one Redis for the job queue and for multiplayer coordination in the app editor, so redis.enabled must be true — the single-instance Redis bundled in the image cannot be shared. Sessions are valid on every replica, so no sticky routing is needed.
The chart refuses to render tooljet.replicas of 2 or more while redis.enabled is false. The database tier is a single PostgreSQL instance by design; the Redis tier is pinned to one data node and one monitor-only Sentinel because ToolJet’s Redis client is not Sentinel-aware.

Troubleshooting

Symptom: cpln helm install reported success, cpln logs returns nothing, and cpln workload get-deployments RELEASE_NAME-tooljet --gvc GVC_NAME -o yaml shows The secret KEYS_SECRET_NAME no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. under status.versions[].message.Cause: The key secret named by secrets.name or the database credentials secret named by postgres.config.credentialsSecretName does not exist. The same applies to an smtp.auth.secretName or redis.redis.auth.fromSecret.name that was set but never created. Check RELEASE_NAME-postgres and RELEASE_NAME-redis the same way.Fix: Create it (see Prerequisites). The deployment recovers on its own once the secret exists; cpln workload force-redeployment RELEASE_NAME-tooljet --gvc GVC_NAME skips the wait.
Symptom: On a fresh install the ToolJet container keeps restarting; cpln workload get-deployments RELEASE_NAME-tooljet --gvc GVC_NAME -o yaml shows an exit code of 137, and the logs end partway through the schema migrations.Cause: tooljet.resources.maxMemory was set below 4Gi. The image bakes a 4096 MB Node heap and the first-boot migrations exceed smaller limits, so the container is killed for running out of memory.Fix: Restore tooljet.resources.maxMemory: 4Gi and upgrade. The migrations complete on the next boot.
Symptom: tooljet: tooljet.replicas >= 2 requires redis.enabled=true — multiple replicas must share an external Redis for job-queue and multiplayer coordination (the in-image Redis is single-instance-only).Cause: tooljet.replicas is 2 or more while redis.enabled is false.Fix: Set redis.enabled: true (see Scaling and Availability), or keep a single replica.
Symptom: tooljet: redis.redis.replicas must stay 1 — ToolJet is not Sentinel-aware ... or tooljet: redis.sentinel.replicas must stay 1 — with a single data node there is no failover target ....Cause: redis.redis.replicas or redis.sentinel.replicas was changed from 1.Fix: Set both back to 1. ToolJet connects to the Redis service name directly, so extra data nodes would receive writes they cannot accept.
Symptom: smtp.enabled: true was applied with helm upgrade, the SMTP_* variables are on the workload, yet invitations and password resets send nothing and the instance still reports mail as disabled.Cause: ToolJet seeds its mail settings from the environment during a first-boot migration only. Values added later reach the container but are never applied.Fix: SMTP has to be part of the initial install (see Email). Enabling it on an existing instance through values is not supported by this template.
Symptom: The render fails with config.username was REMOVED in postgres 3.4.0 and advice about a prerequisite dictionary secret.Cause: Your values file still carries postgres.config.username, postgres.config.password, or postgres.config.database.Fix: Move their values into the database credentials secret as described in Upgrading from 1.0.0.
Symptom: The render fails with postgres.credentials was removed in 1.3.0 or redis.redis.auth.password was removed in tooljet 1.3.0.Cause: Your values file still carries the 1.2.0 database or Redis password keys.Fix: Follow Upgrading from 1.2.0.
Symptom: The ToolJet logs repeat Invalid License Key:Parse error, and /api/health reports the license as invalid or expired.Cause: The image is ToolJet’s LTS build, which includes the licensed edition’s code but runs the free tier without a license key. The license check logs this on every pass.Fix: None needed — this is the free tier working as intended. The same applies to npm warn using --force lines from the image’s entrypoint.

Important Notes

  • Create every prerequisite secret before installing — the key secret (secrets.name, with SECRET_KEY_BASE, LOCKBOX_MASTER_KEY, and PGRST_JWT_SECRET), the database credentials secret (postgres.config.credentialsSecretName) and, with Redis auth on, the Redis password secret. A missing secret wedges the deployment silently; status.versions[].message in cpln workload get-deployments RELEASE_NAME-tooljet --gvc GVC_NAME -o yaml names it.
  • SECRET_KEY_BASE and LOCKBOX_MASTER_KEY are write-once — rotating LOCKBOX_MASTER_KEY makes every stored datasource credential undecryptable. Back the keys up outside Control Plane.
  • Do not lower tooljet.resources.maxMemory below 4Gi — the first boot’s migrations run out of memory below it and the workload never becomes ready.
  • Claim the Super Admin account right after install — the first visitor to complete onboarding owns the instance, and the endpoint is public by default.
  • Configure SMTP at the initial install — enabling it through a later upgrade does nothing.
  • tooljet.replicas of 2 or more requires redis.enabled: true, and both the Redis data node and the Sentinel must stay at one replica.
  • Changing the database password is a database change first — run ALTER ROLE, update the secret, then force-redeploy ToolJet (Rotating the Database Password).
  • Give each release its own database credentials secret — secret names are org-wide, so two releases pointed at one secret share a password.
  • Uninstalling deletes the PostgreSQL volume set and every app, user, and ToolJet Database table in it; your prerequisite secrets are yours and survive.
  • ToolJet is licensed under the AGPL — the deployed image is the LTS build and runs the free tier without a license key.

External References

ToolJet Documentation

Official ToolJet documentation

Environment Variables

Every setting the ToolJet server reads from its environment

ToolJet Database

The built-in PostgREST-backed database and its API

Super Admin

First-run onboarding and instance-wide administration

ToolJet on GitHub

Source code and release notes

ToolJet Template

View the source files, default values, and chart definition