Skip to main content

Overview

NocoDB is a no-code database and smart spreadsheet — a self-hosted alternative to Airtable, Baserow, and Teable — that turns a database into grid, kanban, gallery, and calendar views with forms, webhooks, and a REST API. This template deploys NocoDB Community Edition (web UI, REST and GraphQL APIs, and live updates on port 8080) backed by a bundled PostgreSQL for all metadata and a bundled Redis for job events, caching, and rate limiting, with attachments kept on a persistent volume or in an S3 bucket you own. The default is a single replica over a single-instance PostgreSQL; nocodb.replicas scales the app tier once attachments live in S3, and postgresHA.enabled swaps the database for a highly available cluster.
This template deploys into an existing GVC that you already have — it does not create or manage a GVC.

What Gets Created

Your key secret is not created by the template — see Prerequisites.

Prerequisites

NocoDB signs its auth tokens and encrypts the stored credentials of external data sources with two keys that you supply through a dictionary secret created before installing. The values never pass through Helm values.
1

Create the key secret

The secret holds two random values under exactly these keys:
Set secrets.name to this name. Secrets are org-level, so no GVC flag is involved.
2

Back both values up outside Control Plane

Both keys are write-once: rotating NC_AUTH_JWT_SECRET logs out every user, and changing NC_CONNECTION_ENCRYPT_KEY makes the stored credentials of external data sources undecryptable — upstream has no re-encryption path. Keep a copy somewhere safe.
Create the secret before installing. Installing without it 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:
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-nocodb --gvc GVC_NAME skips the wait.
Everything else works with the defaults. Four optional features need their own setup first:
  • S3 attachment storage (required for more than one replica) — an existing bucket plus either an AWS cloud account and bucket-scoped IAM policy, or a static-key secret for an S3-compatible server. See Attachment Storage on S3.
  • Super-admin bootstrap — a dictionary secret holding NC_ADMIN_EMAIL and NC_ADMIN_PASSWORD. See Super-Admin Bootstrap.
  • Authenticated SMTP — a dictionary secret holding NC_SMTP_USERNAME and NC_SMTP_PASSWORD. See Email.
  • Scheduled database backups — a bucket and provider access for the bundled PostgreSQL. See Backing Up.

Installation

Once your key secret exists, install from the marketplace registry, pointing secrets.name at it and replacing both bundled-component passwords (letters, digits, -, and _ only — both are embedded in connection URLs):
Installing a second NocoDB release in the same org? Also set postgres.config.credentialsSecretName to a name no other release uses — secret names are org-wide. 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

NocoDB Server

nocodb.siteUrl must match the URL browsers actually use. Leave it empty to derive it from the workload’s canonical endpoint; set it, with the https:// scheme, only when you serve NocoDB on a custom domain.

Prerequisite Secret

Super-Admin Bootstrap

By default NocoDB seeds no account and the first person to sign up becomes the super admin. To create the account up front instead, put the credentials in a dictionary secret and reference it by name. The password must be at least 8 characters with an uppercase letter, a digit, and a special character.
NocoDB re-applies these credentials on every boot. If the account’s password is later changed in the UI, the next restart silently reverts it to the value in the secret. Either leave admin.secretName empty or treat the secret as the account’s source of truth.

Attachment Storage

storage.type decides where uploaded files, images, and thumbnails are kept. The default local volume works for a single replica; the bucket, cloud account, and secret setup for s3 is under Attachment Storage on S3.
storage.fileUploadSizeLimit is a byte count, not a size string. An upload over the limit is rejected with HTTP 413 and File too large, not truncated.

Email

SMTP is off by default and a default install works without it — the first visitor still creates the super-admin account and signs in with its password. Member invitations and password-reset emails, however, are delivered only by email.
NocoDB activates its mail plugin only when host, port, and from are all set; the chart fails the render if smtp.enabled is true and any of them is missing. For an authenticated relay, create the credentials secret before installing and set smtp.auth.secretName to its name. The NocoDB identity is granted reveal on exactly that secret.

Access

With publicAccess.enabled: false there is no public endpoint, and an empty nocodb.siteUrl falls back to the internal http://RELEASE_NAME-nocodb.GVC_NAME.cpln.local:8080 address. A change to either access knob takes a couple of minutes to take effect after the upgrade reports success.

Bundled Redis

Redis is required: it carries the job and event pub/sub, the metadata cache, and the rate limiter, and all three are what make more than one replica coherent. It runs with appendonly yes and maxmemory-policy noeviction — an evicted key would silently drop a job event.

Database

Enable exactly one of postgres (single instance, the default) and postgresHA (highly available) — the chart refuses to render both on or both off. NocoDB is wired to the active database automatically, including for its boot migrations. The single instance is the default because on Control Plane the difference between the two modes is minutes of downtime, not data loss. The two paths run different PostgreSQL majors, so pick the mode before you have data — moving an existing database between them is a dump and restore, not a values change. In both modes the chart builds the database credentials secret from postgres.credentials.* for you — nothing to create before installing. The database name stays a plain value because it is written into NocoDB’s NC_DB connection URL at install time; the username and password are read from the secret.
Both bundled passwords seed their component on first boot and are not updated by later value edits. Uninstalling the release deletes the volume sets; reinstall to reset.

Connecting

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

First Run

NocoDB ships no default account. Unless you bootstrap one with admin.secretName, the first person to sign up becomes the super admin — and the signup form is open to anyone who can reach the endpoint.
1

Wait for the NocoDB workload to report ready

PostgreSQL and Redis come up first, then NocoDB applies its meta-database migrations before it starts serving.
2

Sign up and claim the super-admin account

Browse to the canonical endpoint (or the port-forward URL) and create the first account. It receives the super role. Do this as soon as the workload is ready.
3

Close signup

Signup is open by default. Turn on invite-only in Team & Settings inside the app — it is an in-app setting, not a template value.
4

Configure email before inviting anyone

Member invitations and password resets are delivered only by email. Configure SMTP before you invite your team.

Operations

Attachment Storage on S3

Set storage.type: s3 to keep attachments in a bucket you own. This is required for more than one replica, and nothing in the template moves existing attachments between the local volume and the bucket — choose the storage type before uploading content. No attachment volume set is created in this mode.
AWS S3 uses a Control Plane cloud account: no access keys are stored anywhere, and the NocoDB identity obtains temporary credentials at runtime. This is the only supported way to reach AWS S3 — the chart rejects static keys unless storage.s3.endpoint is set.
1

Create a bucket

Create an S3 bucket. Set storage.s3.bucket and storage.s3.region to match.
2

Set up a cloud account

If you do not have one, create a cloud account for your AWS account. Set storage.s3.cloudAccountName to its name.
3

Create a bucket-scoped IAM policy

Create an AWS IAM policy with the JSON below (replace YOUR_BUCKET_NAME with your bucket), then set storage.s3.policyName to the policy’s name:
4

Leave the key secret empty

Keep storage.s3.auth.secretName empty. The template then attaches the cloud account and your policy to the NocoDB identity.

Backing Up

Scheduled backups of the bundled PostgreSQL are off by default. Enable them on whichever database you run — postgres.backup.enabled: true adds the cron workload RELEASE_NAME-postgres-backup; postgresHA.backup.enabled: true adds RELEASE_NAME-postgres-ha-backup. Each run uploads a gzipped SQL dump to your bucket under the configured prefix, covering every base, record, view, and user. Pick a provider and complete the matching setup before installing or upgrading with backups on. The blocks below show the single-instance keys; the HA path takes the same aws / gcp / minio blocks under postgresHA.backup.
1

Create a bucket

Create an S3 bucket. Set backup.aws.bucket and backup.aws.region to match.
2

Set up a cloud account

If you do not have one, create a cloud account for the AWS account holding the bucket. Set backup.aws.cloudAccountName to its name.
3

Create a bucket-scoped IAM policy

Create an IAM policy with the same bucket-scoped JSON shown under Attachment Storage on S3, pointed at the backup bucket, and set backup.aws.policyName to its name.
In HA mode, postgresHA.backup.mode selects logical (a scheduled dump on postgresHA.backup.logical.schedule, using postgresHA.backup.logical.image) or wal-g (continuous WAL archiving every postgresHA.backup.walg.intervalSeconds). On the single-instance path the postgres.backup.image tag must match the PostgreSQL major in postgres.image — change both together if you move off the default. Three things the database dump does not cover: local attachments live on the RELEASE_NAME-nocodb-storage volume set (S3 attachments are already in your bucket), the Redis data is a cache and job stream that rebuilds itself, and your two keys live in the secret you created. The PostgreSQL volume set (RELEASE_NAME-pg-vs or RELEASE_NAME-postgres-ha-vs) takes no scheduled snapshots; a final snapshot is taken when the volume set is deleted and kept 7 days.

Restoring a Backup

Each single-instance backup is a gzipped plain-SQL dump. Restoring means replaying that SQL into the bundled PostgreSQL. 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 database NocoDB already created and migrated on first boot; and no NocoDB replica may be connected while you drop and recreate that database before the replay. For the HA database, follow the restore procedure on the postgres-highly-available page against RELEASE_NAME-postgres-ha-proxy.
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.x

Version 1.1.0 adopted the postgres 3.4.1 template, which stopped taking database credentials as values. NocoDB absorbed that change rather than passing it on — the chart now creates the credentials secret itself — so there is no new prerequisite, only a rename of three keys: Move the three keys, keep the same values so the running database still matches, and upgrade in place. 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 yourself; ignore that advice here, this template creates it. postgres.backup.minio.accessKey and postgres.backup.minio.secretKey were removed the same way: that path now reads a dictionary secret named by postgres.backup.minio.credentialsSecretName (see Backing Up). Version 1.0.1 also moved the bundled postgres-highly-available template to 2.4.2, which turns on etcd history compaction. HA installs still on 1.0.0 should upgrade; compaction stops further growth but cannot shrink a backend that has already grown. If you run the HA database, continue with the section below as well.

Upgrading from 1.1.x

Version 1.2.0 adopted postgres-highly-available 2.5.0, which no longer creates its own credentials secret. The HA database now reads the same chart-created secret as the single-instance path, built from postgres.credentials.*, and the postgresHA.postgres.* keys were removed: Set postgres.credentials.* to exactly the values your running Patroni cluster was initialised with — the database does not pick up a new password from a values change — and drop the old keys. Version 1.2.1 removed postgresHA.backup.minio.accessKey and postgresHA.backup.minio.secretKey the same way; that path now reads postgresHA.backup.minio.credentialsSecretName. An in-place upgrade across this boundary has not been exercised on a live HA install; rehearse it on a throwaway release first.
The first helm upgrade after an install can restart the bundled Redis even when nothing about Redis changed, and NocoDB exits and restarts rather than reconnecting — at a single replica that is a brief outage on a routine config change; a second replica absorbs it. Later upgrades of the same release do not restart Redis.

Scaling and Availability

nocodb.replicas sets how many NocoDB replicas run. Replicas coordinate through the bundled Redis, which carries the job and event pub/sub, the shared metadata cache, and the rate limiter — all three are what make a second replica correct rather than merely present. Rolling upgrades proceed one replica at a time.
nocodb.replicas above 1 requires storage.type: s3. Local attachments live on per-replica volumes, so an attachment uploaded through one replica would return a 404 from another. The chart refuses to render the combination.
Background jobs run inside the web process. Community Edition ships only an in-process queue, so a long import, export, or base duplication dies with the replica running it and has to be re-run. Multiple replicas buy request availability and clean rolling upgrades, not job durability.
Live updates reach the browser over HTTP long-poll (POST /jobs/listen) backed by the Redis pub/sub, not over websockets — a stalled live update is a Redis or /jobs/listen problem. The database tier scales separately: postgresHA.enabled: true (with postgres.enabled: false) replaces the single PostgreSQL with a 3-replica Patroni cluster behind an HAProxy leader endpoint, and postgresHA.replicas sets the Patroni replica count. The bundled Redis is single-instance by design — NocoDB speaks only a plain redis:// URL, so the Sentinel-based Redis template is not used.

Troubleshooting

Symptom: cpln helm install reported success, cpln logs returns nothing, and cpln workload get-deployments RELEASE_NAME-nocodb --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 does not exist. The same applies to an admin.secretName, storage.s3.auth.secretName, or smtp.auth.secretName that was set but never created.Fix: Create it (see Prerequisites). The deployment recovers on its own once the secret exists; cpln workload force-redeployment RELEASE_NAME-nocodb --gvc GVC_NAME skips the wait.
Symptom: On a brand-new install the first NocoDB replica logs Connection terminated unexpectedly (or an [ioredis] write error) and exits once before coming up clean.Cause: The replica started before PostgreSQL or Redis was accepting connections. It restarts automatically and runs its migrations on the retry.Fix: None needed. One such restart on a first install is expected; a replica that keeps restarting is a different problem — check that both bundled passwords use only letters, digits, -, and _.
Symptom: A routine helm upgrade that changed nothing about Redis makes the endpoint return 503 briefly, and the NocoDB logs show an ioredis error followed by an exit.Cause: The first upgrade after an install can restart the bundled Redis, and NocoDB exits rather than reconnecting. It is restarted automatically.Fix: Nothing to repair. Run nocodb.replicas: 2 (with S3 storage) if a single-replica interruption on the first upgrade is unacceptable; later upgrades of the same release do not restart Redis.
Symptom: Installing a second NocoDB release fails with cannot be updated because it is being managed by a different release and creates nothing.Cause: Both releases use the same postgres.config.credentialsSecretName. Secret names are org-wide, and the first release owns that one. Nothing is shared, overwritten, or deleted.Fix: Set postgres.config.credentialsSecretName (and postgresHA.config.credentialsSecretName in HA mode) to a distinct name for the second release and install again.
Symptom: nocodb: nocodb.replicas > 1 requires storage.type: s3 — local attachments live on a per-replica volumeset and would 404 across replicas.Cause: nocodb.replicas is above 1 while storage.type is local.Fix: Complete Attachment Storage on S3 and set storage.type: s3, or keep a single replica.
Symptom: nocodb: static keys (storage.s3.auth.secretName) are only for S3-compatible servers (storage.s3.endpoint set).Cause: storage.s3.auth.secretName is set without a storage.s3.endpoint. AWS S3 is keyless-only in this template.Fix: For AWS, clear storage.s3.auth.secretName and set storage.s3.cloudAccountName and storage.s3.policyName. For an S3-compatible server, set storage.s3.endpoint too.
Symptom: nocodb: enable exactly one database — set either postgres.enabled (single instance, default) or postgresHA.enabled (highly available), not both.Cause: postgres.enabled and postgresHA.enabled are both true, or both false.Fix: To use the HA database set postgresHA.enabled: true and postgres.enabled: false; otherwise leave both at their defaults.
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: Rename them to postgres.credentials.* as described in Upgrading from 1.0.x. Do not create a secret yourself — this template creates it.
Symptom: A webhook aimed at an internal address such as http://WORKLOAD_NAME.GVC_NAME.cpln.local never fires, and the hook log says to set NC_ALLOW_LOCAL_HOOKS=true.Cause: NocoDB’s SSRF guard refuses webhooks to private-network addresses by default, and same-GVC hostnames resolve to private IPs.Fix: Set nocodb.allowLocalWebhooks: true and upgrade. Leave it off if your webhooks only ever call the public internet.
Symptom: An upload fails with HTTP 413 and {"message": "File too large", "error": "Payload Too Large", "statusCode": 413}.Cause: The file exceeded storage.fileUploadSizeLimit (a byte count; the default 20971520 is 20 MiB).Fix: Raise storage.fileUploadSizeLimit, upgrade, and upload the file again.
Symptom: An invitation created in the UI reaches no one, and a password reset never sends a mail.Cause: smtp.enabled is false, or smtp.auth.secretName names a secret that does not exist.Fix: Configure Email with smtp.enabled: true (and smtp.auth.secretName for an authenticated relay), then re-send the invitation.
Symptom: A password changed in the UI stops working after the workload restarts; the previous one works again.Cause: admin.secretName is set, and NocoDB re-applies NC_ADMIN_EMAIL and NC_ADMIN_PASSWORD from that secret on every boot.Fix: Either clear admin.secretName after the first boot, or change the password in the secret (then run cpln workload force-redeployment RELEASE_NAME-nocodb --gvc GVC_NAME so the new value is picked up) and treat the secret as the source of truth.

Important Notes

  • Create the key secret before installing — secrets.name must name an existing dictionary secret holding NC_AUTH_JWT_SECRET and NC_CONNECTION_ENCRYPT_KEY. A missing secret wedges the deployment silently.
  • Both keys are write-once — rotating NC_AUTH_JWT_SECRET logs out every user, and changing NC_CONNECTION_ENCRYPT_KEY makes the stored credentials of external data sources undecryptable. Back both values up outside Control Plane.
  • Sign up immediately after install — signup is open by default, so the first visitor to sign up becomes the super admin. Then turn on invite-only in Team & Settings.
  • With SMTP off, invitations and password resets cannot be delivered — configure smtp.* before inviting collaborators.
  • nocodb.replicas above 1 requires storage.type: s3 — local attachments are per-replica; the chart refuses to render the combination.
  • AWS S3 is keyless only — a cloud account plus a bucket-scoped IAM policy; static keys are accepted only with an S3-compatible storage.s3.endpoint.
  • storage.fileUploadSizeLimit is a byte count — the default 20971520 is 20 MiB; over-limit uploads are rejected with 413, not truncated.
  • Webhooks to same-GVC targets are blocked by default — set nocodb.allowLocalWebhooks: true to fire webhooks at other workloads in your GVC.
  • admin.secretName re-applies on every boot — a password changed in the UI reverts at the next restart. Leave it empty or treat the secret as the source of truth.
  • Change postgres.credentials.password and redis.auth.password before installing — both seed their component on first boot, are not updated by later value edits, and must use only letters, digits, -, and _.
  • Enable exactly one database — postgres (PostgreSQL 18, default) or postgresHA (PostgreSQL 17). Choose before you have data; switching is a dump and restore.
  • Give each release its own postgres.config.credentialsSecretName — secret names are org-wide, and a second release on the same name is refused at install.
  • Set nocodb.siteUrl when NocoDB sits behind a custom domain, with the scheme — it drives invitation and password-reset links and the auth cookie’s secure flag.
  • Background jobs are in-process — a long import, export, or base duplication does not survive the replica running it and must be re-run.
  • Uninstalling deletes the volume sets and every base and local attachment in them; your key secret is yours and survives.
  • MCP endpoints are created per base in the UI (base → Settings → MCP Server) and authenticate with an xc-mcp-token; account-level MCP and OAuth are Enterprise features and are not available on this edition.
  • SSO/SAML/OIDC, audit logs, and row-level security are Enterprise features — they ship in the same image but need a purchased licence key that this template never sets.
  • NocoDB Community Edition is fair-code — the Sustainable Use License permits self-hosting for your own use; offering NocoDB as a hosted service to others requires a commercial licence.

External References

NocoDB Documentation

Official NocoDB product documentation

Self-Hosting Guide

Deployment, upgrades, and operational guidance

Environment Variables

Every setting the NocoDB server reads from its environment

NocoDB on GitHub

Source code and release notes

NocoDB Template

View the source files, default values, and chart definition