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 port8080) 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.
What Gets Created
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.Create the key secret
secrets.name to this name. Secrets are org-level, so no GVC flag is involved.Back both values up outside Control Plane
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.- 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_EMAILandNC_ADMIN_PASSWORD. See Super-Admin Bootstrap. - Authenticated SMTP — a dictionary secret holding
NC_SMTP_USERNAMEandNC_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, pointingsecrets.name at it and replacing both bundled-component passwords (letters, digits, -, and _ only — both are embedded in connection URLs):
postgres.config.credentialsSecretName to a name no other release uses — secret names are org-wide.
Other ways to install and manage the template:
UI
CLI
Terraform
Pulumi
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.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.
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
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 withappendonly yes and maxmemory-policy noeviction — an evicted key would silently drop a job event.
Database
Enable exactly one ofpostgres (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.
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.
Connecting
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 withadmin.secretName, the first person to sign up becomes the super admin — and the signup form is open to anyone who can reach the endpoint.
Wait for the NocoDB workload to report ready
Sign up and claim the super-admin account
super role. Do this as soon as the workload is ready.Close signup
Configure email before inviting anyone
Operations
Attachment Storage on S3
Setstorage.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 (keyless)
- S3-compatible (MinIO and others)
storage.s3.endpoint is set.Create a bucket
storage.s3.bucket and storage.s3.region to match.Set up a cloud account
storage.s3.cloudAccountName to its name.Create a bucket-scoped IAM policy
YOUR_BUCKET_NAME with your bucket), then set storage.s3.policyName to the policy’s name:Leave the key secret empty
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.
- AWS S3
- Google Cloud Storage
- MinIO / S3-compatible
Create a bucket
backup.aws.bucket and backup.aws.region to match.Set up a cloud account
backup.aws.cloudAccountName to its name.Create a bucket-scoped IAM policy
backup.aws.policyName to its name.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 iscpln workload exec with --stdin and a base64 wrapper on both ends — raw binary piped through exec is corrupted:
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.
Upgrading from 1.0.x
Version 1.1.0 adopted thepostgres 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:
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 adoptedpostgres-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:
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.
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.
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
Deployment never becomes ready and the logs are empty
Deployment never becomes ready and the logs are empty
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.One crash in the logs on a fresh install
One crash in the logs on a fresh install
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 _.Brief outage on the first helm upgrade
Brief outage on the first helm upgrade
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.Second install refused as managed by a different release
Second install refused as managed by a different release
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.Render fails because replicas above 1 require s3 storage
Render fails because replicas above 1 require s3 storage
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.Render fails because static keys are only for S3-compatible servers
Render fails because static keys are only for S3-compatible servers
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.Render fails asking you to enable exactly one database
Render fails asking you to enable exactly one database
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.Upgrade from 1.0.x fails asking you to create a dictionary secret
Upgrade from 1.0.x fails asking you to create a dictionary secret
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.Webhook to another workload in the GVC is refused
Webhook to another workload in the GVC is refused
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.Attachment upload rejected with 413 File too large
Attachment upload rejected with 413 File too large
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.Invitations or password-reset emails never arrive
Invitations or password-reset emails never arrive
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.Super-admin password reverts after a restart
Super-admin password reverts after a restart
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.namemust name an existing dictionary secret holdingNC_AUTH_JWT_SECRETandNC_CONNECTION_ENCRYPT_KEY. A missing secret wedges the deployment silently. - Both keys are write-once — rotating
NC_AUTH_JWT_SECRETlogs out every user, and changingNC_CONNECTION_ENCRYPT_KEYmakes 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.replicasabove1requiresstorage.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.fileUploadSizeLimitis a byte count — the default20971520is 20 MiB; over-limit uploads are rejected with413, not truncated.- Webhooks to same-GVC targets are blocked by default — set
nocodb.allowLocalWebhooks: trueto fire webhooks at other workloads in your GVC. admin.secretNamere-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.passwordandredis.auth.passwordbefore 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) orpostgresHA(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.siteUrlwhen 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.