> ## Documentation Index
> Fetch the complete documentation index at: https://docs.controlplane.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ToolJet

> Deploy ToolJet on Control Plane using the Template Catalog. Open-source low-code platform for internal tools — visual app builder, 50+ datasource connectors, and the built-in ToolJet Database, backed by PostgreSQL with optional Redis for multi-replica scaling.

## Overview

ToolJet is an open-source, low-code platform for building internal tools: a visual app builder with 50+ datasource connectors and the built-in ToolJet Database. This template deploys the ToolJet server — UI and API on port `3000` — backed by a PostgreSQL instance that holds both the application database and the ToolJet Database, with optional Redis for running more than one replica.

### Architecture

* **ToolJet server** — A standard HTTP workload serving the UI and REST API on port `3000`. It runs its database migrations automatically on boot and scales horizontally through `tooljet.replicas`. PostgREST (which serves the ToolJet Database API) and a single-instance fallback Redis are bundled inside the official image, so no extra workloads are deployed for them.
* **PostgreSQL** — The [postgres](/template-catalog/templates/postgres) template as a subchart. A single instance holds two databases, both created automatically on first boot: `tooljet` (apps, users, and encrypted datasource credentials) and `tooljet_db` (the ToolJet Database, served through the in-image PostgREST). ToolJet's boot scripts also create a `sample_db` with sample data.
* **Redis + Sentinel** *(optional)* — The [redis](/template-catalog/templates/redis) template as a subchart, pinned to one data node and one sentinel. It carries the shared job queue and multiplayer coordination between replicas, and is required whenever `tooljet.replicas` is 2 or more.

### What Gets Created

* **Standard ToolJet Workload** — The ToolJet server on port `3000` (`{release}-tooljet`), with `tooljet.replicas` replicas and configurable CPU and memory.
* **Stateful PostgreSQL Workload** — One PostgreSQL instance from the subchart, with its own volume set (10 GiB by default).
* **Redis and Sentinel Workloads** *(optional)* — One Redis data node and one sentinel, created when `redis.enabled` is `true`.
* **Secret** — A template-created dictionary secret (`{release}-tooljet-db`) holding the database username and password used to assemble ToolJet's `PG_*`, `TOOLJET_DB_*`, and `PGRST_DB_URI` settings. Your prerequisite key secret is *not* created by the template — see [Prerequisites](#prerequisites).
* **Identity & Policy** — An identity bound to the ToolJet workload, and a policy granting it `reveal` on exactly the secrets it reads: the database secret, your prerequisite key secret, and — when configured — the SMTP and Redis password secrets.

<Note>
  This template does not create a GVC. You must deploy it into an existing GVC.
</Note>

## Prerequisites

ToolJet reads its root-of-trust keys from a [dictionary secret](/guides/create-secret/dictionary) that you create **before** installing. The keys are never passed through values.

<Steps>
  <Step title="Create the key secret">
    Create a dictionary secret containing the three keys ToolJet requires, generated the same way upstream's setup scripts generate them:

    ```bash theme={null}
    cpln secret create-dictionary --name my-tooljet-secrets \
      --entry SECRET_KEY_BASE=$(openssl rand -hex 64) \
      --entry LOCKBOX_MASTER_KEY=$(openssl rand -hex 32) \
      --entry PGRST_JWT_SECRET=$(openssl rand -hex 32)
    ```

    | Key                  | Purpose                                                                      |
    | -------------------- | ---------------------------------------------------------------------------- |
    | `SECRET_KEY_BASE`    | Signs sessions and cookies.                                                  |
    | `LOCKBOX_MASTER_KEY` | Encrypts every stored datasource credential.                                 |
    | `PGRST_JWT_SECRET`   | Signs the JWTs the in-image PostgREST accepts for ToolJet Database requests. |
  </Step>

  <Step title="Point the template at it">
    Set `secrets.name` to the secret's name (default `my-tooljet-secrets`). Secrets are org-level, so no GVC flag is involved.
  </Step>

  <Step title="Back up the keys">
    Store a copy of all three values somewhere safe, outside Control Plane.
  </Step>
</Steps>

<Warning>
  Create the secret **before** installing. A missing secret pauses the deployment waiting on it — the install looks broken until the secret exists. `SECRET_KEY_BASE` and `LOCKBOX_MASTER_KEY` are write-once: rotating `LOCKBOX_MASTER_KEY` makes every datasource credential ToolJet has stored undecryptable.
</Warning>

For authenticated SMTP, you also need a second dictionary secret holding `SMTP_USERNAME` and `SMTP_PASSWORD` — see [Email](#email). Everything else works with the defaults.

Once your key secret exists, install the template using your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## First Run

ToolJet ships no default account. The first person to open the endpoint completes the Super Admin onboarding and creates the initial workspace, so open the instance and claim it as soon as the workload reports ready.

<Steps>
  <Step title="Wait for the first boot to finish">
    The container waits for PostgreSQL, creates both databases, and runs all of its schema migrations before it starts serving. Expect roughly two minutes once the image is cached on the location, and noticeably longer on the very first pull — the ToolJet image is multi-gigabyte.
  </Step>

  <Step title="Open the endpoint">
    Browse to the canonical `*.cpln.app` endpoint of the `{release}-tooljet` workload and complete the Super Admin form.
  </Step>

  <Step title="Invite your team">
    Invitations are sent by email, so configure [SMTP](#email) at install time if you plan to invite users.
  </Step>
</Steps>

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
tooljet:
  image: tooljet/tooljet:v3.20.204-lts
  replicas: 1 # >=2 requires redis.enabled=true (shared job queue + multiplayer coordination)
  host: "" # public base URL ToolJet advertises, with https://; empty = derive from the canonical endpoint
  resources:
    minCpu: 500m
    maxCpu: 2000m
    minMemory: 1Gi
    maxMemory: 4Gi # first-boot migrations OOM below this (the image bakes a 4096MB Node heap)

secrets:
  name: my-tooljet-secrets # dictionary secret with the three keys — MUST exist before install

smtp:
  enabled: false # only takes effect at INITIAL install (see Email)
  host: smtp.example.com
  port: 587
  fromEmail: no-reply@example.com
  auth:
    secretName: "" # optional dictionary secret with SMTP_USERNAME + SMTP_PASSWORD; empty = unauthenticated relay

publicAccess:
  enabled: true # HTTPS UI + API on the auto *.cpln.app endpoint; false = internal-only

internalAccess:
  type: same-gvc # options: none, same-gvc, same-org, workload-list
  workloads: [] # used only with workload-list, e.g. //gvc/GVC_NAME/workload/WORKLOAD_NAME

postgres: # app DB + ToolJet Database
  image: postgres:16
  config:
    username: tooljet
    password: change-me-tooljet-pg # change before installing
    database: tooljet # tooljet_db is auto-created alongside it
  resources:
    minCpu: 250m
    maxCpu: 1000m
    minMemory: 512Mi
    maxMemory: 1Gi
  volumeset:
    capacity: 10 # initial capacity in GiB (minimum is 10)

redis: # optional — required for tooljet.replicas >= 2
  enabled: false
  redis:
    image: redis:7.4
    replicas: 1 # keep at 1 — ToolJet is not Sentinel-aware
    auth:
      password:
        enabled: false # true = require AUTH, wired into ToolJet as REDIS_PASSWORD
        value: change-me-tooljet-redis
    resources:
      cpu: 200m
      memory: 256Mi
      minCpu: 80m
      minMemory: 128Mi
  sentinel:
    image: redis:7.4
    replicas: 1 # monitor only
    resources:
      cpu: 200m
      memory: 256Mi
      minCpu: 80m
      minMemory: 128Mi
```

### ToolJet Server

* `image` — The official ToolJet LTS image.
* `replicas` — Number of ToolJet replicas. Anything above `1` requires `redis.enabled: true`; the chart fails the render with a clear message otherwise.
* `host` — The public base URL ToolJet advertises in links and redirects, including the `https://` scheme. Leave it empty to derive it from the workload's canonical endpoint; set it when you serve ToolJet on a custom domain.
* `resources` — CPU and memory bounds for the ToolJet container.

<Warning>
  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 by the out-of-memory reaper at smaller limits, leaving the workload in a crash loop that never finishes migrating.
</Warning>

### Databases

One PostgreSQL instance from the [postgres](/template-catalog/templates/postgres) subchart backs the whole deployment, and ToolJet's boot scripts create the databases it needs:

| Database     | Contents                                                                                     |
| ------------ | -------------------------------------------------------------------------------------------- |
| `tooljet`    | Apps, users, workspaces, settings, and encrypted datasource credentials.                     |
| `tooljet_db` | The ToolJet Database — user tables created in the UI, served through the in-image PostgREST. |
| `sample_db`  | Sample data created by ToolJet's boot scripts.                                               |

**Change `postgres.config.password` before installing** — it seeds the database on first boot and cannot be changed afterwards by editing values. `postgres.volumeset.capacity` sets the initial data volume size in GiB (minimum 10), and `postgres.resources` bounds the database container.

<Note>
  The ToolJet Database is a core part of ToolJet 3.x and cannot be turned off.
</Note>

### Scaling

`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.

```yaml theme={null}
tooljet:
  replicas: 2
redis:
  enabled: true
```

* `redis.enabled` — Deploys the [redis](/template-catalog/templates/redis) subchart and points ToolJet at it. When disabled, a single-replica ToolJet uses the Redis inside its own container.
* `redis.redis.auth.password.enabled` / `.value` — Require `AUTH` on the Redis data node and wire the password into ToolJet. When enabled, the password is stored in a template-created secret that the ToolJet identity is granted `reveal` on.
* `redis.redis.resources` / `redis.sentinel.resources` — CPU and memory bounds for the Redis and sentinel containers.

<Warning>
  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 rejects any other value at render time.
</Warning>

Sessions stay valid across replicas, and long-lived websocket connections — the ones the multiplayer app editor uses — are not cut short by the workload request timeout.

### Access

* `publicAccess.enabled` — Serve the UI and API on the auto-assigned `*.cpln.app` HTTPS endpoint (default). Set to `false` for an internal-only instance: external requests are then refused at the edge, and in-GVC callers still reach it per `internalAccess`.
* `internalAccess.type` — Controls which workloads can reach ToolJet over the internal network:

| Type            | Description                                                            |
| --------------- | ---------------------------------------------------------------------- |
| `none`          | No internal access.                                                    |
| `same-gvc`      | Allow access from all workloads in the same GVC (default).             |
| `same-org`      | Allow access from all workloads in the same organization.              |
| `workload-list` | Allow access only from workloads listed in `internalAccess.workloads`. |

<Note>
  Firewall changes take a minute or two to propagate after a `helm upgrade` reports success.
</Note>

### 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.

```yaml theme={null}
smtp:
  enabled: true
  host: smtp.example.com
  port: 587
  fromEmail: no-reply@example.com
  auth:
    secretName: my-tooljet-smtp # dictionary secret with SMTP_USERNAME + SMTP_PASSWORD
```

For an authenticated relay, create the credentials secret before installing and reference it by name:

```bash theme={null}
cpln secret create-dictionary --name my-tooljet-smtp \
  --entry SMTP_USERNAME=apikey --entry SMTP_PASSWORD=YOUR_PASSWORD
```

Leave `smtp.auth.secretName` empty for a relay that does not require authentication. When it is set, the ToolJet identity is granted `reveal` on exactly that secret.

<Warning>
  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 are applied to the workload but ToolJet keeps mail disabled. Decide before you install.
</Warning>

## Connecting

| What                       | Value                                                                                                                              |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Public UI / API            | `https://<canonical>.cpln.app` — `status.canonicalEndpoint` of `{release}-tooljet` (`cpln workload get {release}-tooljet -o yaml`) |
| First-run onboarding       | `https://<canonical>.cpln.app/setup`                                                                                               |
| Health check               | `https://<canonical>.cpln.app/api/health` — unauthenticated                                                                        |
| Internal (same GVC)        | `http://{release}-tooljet.{gvc}.cpln.local:3000`                                                                                   |
| Login                      | The Super Admin account created during first-run onboarding                                                                        |
| PostgreSQL (internal)      | `{release}-postgres.{gvc}.cpln.local:5432`, credentials from `postgres.config`                                                     |
| Redis (internal, optional) | `{release}-redis.{gvc}.cpln.local:6379`                                                                                            |

## Important Notes

* **Create the key secret before installing** — `secrets.name` must point at an existing dictionary secret with `SECRET_KEY_BASE`, `LOCKBOX_MASTER_KEY`, and `PGRST_JWT_SECRET`. A missing secret pauses the deployment until the secret is created.
* **`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.
* **Configure SMTP at initial install** — enabling it via a later upgrade silently does nothing.
* **`tooljet.replicas` of 2 or more requires `redis.enabled: true`**, and both the Redis data node and sentinel must stay at one replica.
* **Change `postgres.config.password` before installing** — it seeds the database on first boot and is not updated by later value edits.
* **All ToolJet state lives in PostgreSQL** — apps, users, and ToolJet Database tables survive restarts and upgrades. Uninstalling deletes the database volume set and everything in it.
* **ToolJet is licensed under the AGPL** — the deployed image is the LTS build and runs the free tier without a license key.

## External References

<CardGroup cols={2}>
  <Card title="ToolJet Documentation" icon="book" href="https://docs.tooljet.ai/docs/">
    Official ToolJet documentation
  </Card>

  <Card title="Environment Variables" icon="gear" href="https://docs.tooljet.ai/docs/setup/env-vars/">
    Every setting the ToolJet server reads from its environment
  </Card>

  <Card title="ToolJet Database" icon="database" href="https://docs.tooljet.ai/docs/tooljet-db/tooljet-database/">
    The built-in PostgREST-backed database and its API
  </Card>

  <Card title="Super Admin" icon="user-shield" href="https://docs.tooljet.ai/docs/user-management/role-based-access/super-admin/">
    First-run onboarding and instance-wide administration
  </Card>

  <Card title="ToolJet on GitHub" icon="github" href="https://github.com/ToolJet/ToolJet">
    Source code and release notes
  </Card>

  <Card title="ToolJet Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/tooljet">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
