← All templates · Productivity
Deploy NocoDB in one click
A no-code database: tables as spreadsheets, forms, kanban boards and calendars, with an API
A self-hosted alternative to Airtable.
What is NocoDB?
NocoDB is a no-code database platform: tables look and work like a spreadsheet, and each one can also be seen as a form, a gallery, a kanban board, a calendar, a map or a Gantt chart. Fields hold text, numbers, dates, selections, attachments, formulas, links to other tables, lookups and rollups. Every table has a REST API, webhooks fire when records are created, updated or deleted, and tables can be imported from Airtable, CSV, Excel and JSON.
Teams use NocoDB in place of Airtable to keep a CRM, an inventory, a content calendar or any shared list in a database they control. This template runs the free Community edition with PostgreSQL, makes the super admin from the fields before NocoDB answers anyone, and closes sign-up, so people join only by invitation. The catch: NocoDB’s Sustainable Use License allows internal and personal use but not reselling it, and SSO and permissions per table and field are in the paid self-hosted plans.
Hosting NocoDB on Pethost
- You sign in to Pethost with a passkey, GitHub or Google. No machine yet? You pick a plan, and the link waits until it is ready.
- New project opens at NocoDB. You fill in what it asks for and click Create project: Email, Admin password.
- In a minute or two NocoDB is live at its own address with HTTPS. Its secrets are made at random, and its data is in the nightly backup.
- It is a project like any other: you or your agent can change it, roll it back or restore it.
Questions about NocoDB
Is NocoDB free?
The self-hosted Community edition is free, with unlimited records and seats, under NocoDB’s Sustainable Use License: you may use it inside your own business or for personal use, but not sell it to others. Paid self-hosted plans start at $24 per seat a month, billed yearly, and add SSO and permissions per table and field.
NocoDB vs Airtable: what is the difference?
Both show tables as spreadsheets with forms, kanban and galleries. Airtable runs only in its own cloud, priced per seat, while NocoDB runs where you deploy it, and its Community edition sets no limit on records.
Can I import my Airtable bases into NocoDB?
Yes. NocoDB imports a base from its shared link with an Airtable personal access token that can read records, bringing tables, views and records over. Formula fields do not come over, and a shared view’s link brings only that one table.
Does NocoDB have an API?
Yes. Every table has a REST API, called with an API token, and webhooks send a request when a record is created, updated or deleted, so other apps and scripts can read and write the data.
How do I add people to NocoDB?
In Members & teams → Add Members, by email or with a private invite link, choosing their role. This template closes public sign-up, so nobody joins without one. NocoDB emails invitations once NC_SMTP_HOST and the other NC_SMTP_ settings are in the project’s .env.
How much memory and disk does NocoDB need?
NocoDB takes about 800 MB of memory with Postgres, and its database grows with your records; attachments take what their files take. On Pethost the Starter plan is enough for it, with room for other apps beside it.
NocoDB Docker Compose file
The template is this compose.yaml and the variables written into the project’s .env as it is created. Pethost runs the file as it is written.
Containers: nocodb (nocodb/nocodb:2026.10.0), postgres (postgres:18-alpine).
Volumes, in the nightly backup: data, db.
services:
nocodb:
image: nocodb/nocodb:2026.10.0
restart: unless-stopped
# Any setting of NocoDB can be added to the project's .env, such as NC_SMTP_HOST and the other
# NC_SMTP_ settings, which send its invitations and password resets by email.
env_file: .env
environment:
NC_DB: pg://postgres:5432?u=nocodb&p=${POSTGRES_PASSWORD}&d=nocodb
NC_AUTH_JWT_SECRET: ${JWT_SECRET}
NC_SITE_URL: ${URL}
# The super admin is made from these at the first start, before NocoDB answers anyone, and
# its email and password are set again from them at every start: change them here.
NC_ADMIN_EMAIL: ${ADMIN_EMAIL}
NC_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
# Uploaded files are served only to those signed in, through links that expire.
NC_SECURE_ATTACHMENTS: "true"
# A new NocoDB lets anyone sign up, and only its super admin closes that, in Account → Setup.
# So until that setting has been saved once, NocoDB runs on port 8081, which nobody reaches,
# and the super admin closes sign-up there; only then does it answer on 8080. Turned on again
# in NocoDB later, sign-up stays open.
command:
- sh
- -c
- |
set -e
cd /usr/src/app
if ! node -e '
const { Client } = require("pg");
const url = new URL(process.env.NC_DB);
const params = url.searchParams;
const connection = { host: url.hostname, port: Number(url.port), user: params.get("u"), password: params.get("p"), database: params.get("d") };
(async () => {
for (let i = 0; i < 60; i++) {
const db = new Client(connection);
try {
await db.connect();
const result = await db.query("select 1 from nc_store where key = $$1", ["nc-app-settings"]);
process.exit(result.rowCount > 0 ? 0 : 1);
} catch (error) {
// No such table: a new database, which the migrations of NocoDB have yet to fill.
if (error.code === "42P01") process.exit(1);
await db.end().catch(() => {});
await new Promise((done) => setTimeout(done, 1000));
}
}
process.exit(1);
})();
'; then
PORT=8081 node --no-wasm-dynamic-tiering --no-wasm-tier-up docker/index.js &
setup=$$!
node -e '
const base = "http://127.0.0.1:8081";
const call = async (path, body, token) => {
const response = await fetch(base + path, {
method: "POST",
headers: { "content-type": "application/json", ...(token ? { "xc-auth": token } : {}) },
body: JSON.stringify(body)
});
if (!response.ok) throw new Error(path + ": " + response.status + " " + (await response.text()));
return response.json();
};
const closeSignUp = async () => {
const { token } = await call("/api/v1/auth/user/signin", { email: process.env.NC_ADMIN_EMAIL, password: process.env.NC_ADMIN_PASSWORD });
await call("/api/v1/app-settings", { invite_only_signup: true }, token);
};
(async () => {
let failure;
for (let i = 0; i < 300; i++) {
try {
return await closeSignUp();
} catch (error) {
failure = error;
await new Promise((done) => setTimeout(done, 1000));
}
}
console.error(failure);
process.exit(1);
})();
'
kill $$setup
wait $$setup || true
fi
exec /usr/src/appEntry/start.sh
volumes:
- data:/usr/app/data
depends_on:
postgres:
condition: service_healthy
# The port listens before NocoDB is ready: the deploy waits for its health.
healthcheck:
test: ["CMD-SHELL", "wget -q --tries=1 --spider http://127.0.0.1:8080/api/v1/health || exit 1"]
interval: 5s
timeout: 5s
retries: 5
start_period: 120s
postgres:
image: postgres:18-alpine
restart: unless-stopped
environment:
POSTGRES_DB: nocodb
POSTGRES_USER: nocodb
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U nocodb -d nocodb"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
volumes:
data:
db:
More in Productivity
- MealieA recipe manager and meal planner
- RyotA tracker for films, shows, books, games and workouts
- VikunjaTo-do lists and projects, with kanban and Gantt views
- ExcalidrawA whiteboard for hand-drawn diagrams and sketches, with live collaboration
- OdooBusiness apps in one: CRM, sales, invoicing, inventory, website, projects and more
- PLANKAKanban boards for projects and teams, updated for everyone in real time