Skip to content
SumGuy's Ramblings
Go back

NocoDB: Because Airtable Doesn't Need to Know Your Business

Airtable Is a Great Product That Costs Too Much for What It Is

Airtable is genuinely useful: spreadsheet interface, multiple view types, API access, automations, collaboration. But $20/user/month for the Pro plan — which you need for anything beyond toy usage — adds up fast. And then your data lives in their database, and your team’s workflows are locked to their platform.

NocoDB is the “wait, this is just a UI on top of a SQL database” realization, packaged into a product. You connect it to your existing Postgres, MySQL, SQLite, or SQL Server database, and you get Airtable’s view types, a RESTful API auto-generated from your tables, webhooks, and team collaboration — on hardware you control.

It’s not a perfect Airtable replacement. But for internal tooling, home lab dashboards, and anything where “we’re paying Airtable $X00/month to put a pretty face on a database” is the current situation, it’s a very solid option.

What NocoDB Actually Is

Underneath the spreadsheet interface, NocoDB is a Rails + Vue application that talks to your SQL database and presents it as a collaborative grid. Here’s what that means practically:

This is the important architectural distinction from Airtable: NocoDB is a view layer, not a data layer. Your Postgres database doesn’t know or care that NocoDB exists.

Docker Compose Setup

# docker-compose.yml
version: '3'
services:
  nocodb:
    image: nocodb/nocodb:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      NC_DB: "pg://db:5432?u=nocodb&p=supersecret&d=nocodb"
      NC_AUTH_JWT_SECRET: "your-random-jwt-secret-here"
      # Optional: disable signup for private instances
      NC_DISABLE_TELE: "true"  # Disable telemetry
    depends_on:
      - db
    volumes:
      - nocodb-data:/usr/app/data

  db:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: nocodb
      POSTGRES_USER: nocodb
      POSTGRES_PASSWORD: supersecret
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  nocodb-data:
  postgres-data:
docker compose up -d

# Access at http://localhost:8080
# Create your first admin account in the UI

NocoDB uses its own Postgres database for metadata (views, users, API tokens) while connecting to your target databases separately.

Connecting to an Existing Database

This is where NocoDB earns its keep. You have a Postgres database full of actual data. NocoDB reads it directly.

In the NocoDB UI:

  1. Create a new BaseConnect to existing database
  2. Choose database type: PostgreSQL, MySQL, SQLite, etc.
  3. Enter connection details:
Host: your-postgres-server
Port: 5432
Database: your_app_db
User: readonly_user
Password: password
Schema: public

NocoDB will introspect the database, find all tables, and create a workspace where each table becomes a sheet. Column types are inferred from SQL types:

Foreign keys are recognized and become link fields — you can browse related records inline.

For production use, create a read-only database user for the NocoDB connection if you don’t need write access from the UI:

CREATE USER nocodb_reader WITH PASSWORD 'readonlypass';
GRANT CONNECT ON DATABASE your_app_db TO nocodb_reader;
GRANT USAGE ON SCHEMA public TO nocodb_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO nocodb_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO nocodb_reader;

NocoDB’s multiple view types are what make it more useful than a plain database GUI.

Grid View (Default)

Standard spreadsheet. Filter, sort, group, inline editing. This is what you use for bulk data management.

# Add a filter in the UI:
Filter: status = 'active' AND created_at > '2024-01-01'

# Group by a column:
Group by: department

# Sort:
Sort by: created_at (descending)

Cards with images. Useful for product catalogs, media libraries, contact lists. Pick an “attachment” column as the card image, a text column as the title.

Practical use: you have a table of products with a thumbnail_url column. Gallery view makes it look like an actual product catalog instead of a spreadsheet.

Kanban View

Columns based on a single-select field. Drag cards between columns to update the field value.

-- In your database
ALTER TABLE tasks ADD COLUMN status VARCHAR(50) DEFAULT 'todo';
-- With values: 'todo', 'in_progress', 'review', 'done'

NocoDB turns this into a kanban board where dragging a card updates the status column in the database. Your application code reading that same table sees the updated status immediately.

Calendar View

Requires a date column. Shows records on a calendar based on their date value. Useful for scheduling, event management, due dates.

Auto-Generated REST API

Every table in NocoDB automatically gets a REST API. No configuration required.

# Get your API token from: User settings → API tokens

# List records
curl -X GET \
  -H "xc-token: YOUR_API_TOKEN" \
  "http://localhost:8080/api/v1/db/data/noco/YOUR_BASE_ID/YOUR_TABLE_NAME?limit=25&offset=0"

# Filter and sort
curl -X GET \
  -H "xc-token: YOUR_API_TOKEN" \
  "http://localhost:8080/api/v1/db/data/noco/YOUR_BASE_ID/tasks?where=(status,eq,todo)&sort=-created_at"

# Create a record
curl -X POST \
  -H "xc-token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "New task", "status": "todo", "assignee": "alice"}' \
  "http://localhost:8080/api/v1/db/data/noco/YOUR_BASE_ID/tasks"

# Update a record
curl -X PATCH \
  -H "xc-token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status": "done"}' \
  "http://localhost:8080/api/v1/db/data/noco/YOUR_BASE_ID/tasks/ROW_ID"

# Swagger UI available at:
# http://localhost:8080/api/v1/db/meta/projects/YOUR_BASE_ID/swagger

The Swagger UI documents every endpoint automatically. This is genuinely useful for letting team members explore the API without reading documentation.

Webhooks

NocoDB supports webhooks for table events: record created, updated, deleted.

In the UI: Table → Toolbar → Webhook → Add new webhook

{
  "title": "Notify Slack on new task",
  "event": "after.insert",
  "condition": true,
  "url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
  "method": "POST",
  "body": {
    "text": "New task created: {{record.title}} assigned to {{record.assignee}}"
  }
}

Webhooks support template variables from the record. Combine with n8n or a simple webhook receiver for more complex workflows.

NocoDB vs Baserow vs Grist

Three self-hosted Airtable alternatives, three different philosophies:

FeatureNocoDBBaserowGrist
Connect to existing DBYesNo (manages its own)No
Spreadsheet + formulasBasicBasicFull spreadsheet formulas
Offline supportNoNoYes (desktop app)
API auto-generationYesYesYes
Python/JS scriptingNoNoYes
Setup complexityLowLowMedium
Best forExisting database UIGreenfield data appsPower spreadsheet users

Choose NocoDB when you have an existing database and want to put a UI on it without migrating data.

Choose Baserow when you’re starting fresh and want a simpler, more Airtable-like experience with better UI polish.

Choose Grist when you need actual spreadsheet formulas, Python scripting, or a desktop app for offline use.

Performance with Large Datasets

NocoDB is a frontend — it queries your database on demand. Performance depends on your database:

-- Add indexes for columns you filter/sort frequently
CREATE INDEX idx_tasks_status ON tasks(status);
CREATE INDEX idx_tasks_created_at ON tasks(created_at DESC);
CREATE INDEX idx_tasks_assignee ON tasks(assignee);

-- For full-text search on text columns
CREATE INDEX idx_tasks_title_gin ON tasks USING gin(to_tsvector('english', title));

With proper indexing, NocoDB handles hundreds of thousands of rows without trouble. Without indexing, a filter query on an unindexed column in a table with 100k rows will be painfully slow — NocoDB will execute the query and wait, same as any other client.

The NocoDB pagination defaults to 25 records per page. For large tables, always use the API with proper limit and offset parameters rather than loading everything.

Team Collaboration

NocoDB supports multiple users with role-based access:

Invite team members at the Base level or the Table level. Different tables can have different access levels.

For internal tooling: give the ops team Editor access to the tickets table, give engineers Viewer access to the customer data table. The same NocoDB instance, the same database, different levels of access per team.

When NocoDB Is the Right Tool

It makes the most sense for:

It’s less appropriate for:

The $0/month price point covers a lot of its limitations.


Share this post on:

Previous Post
Docker Logging: From "Where Did My Logs Go?" to Centralized Bliss
Next Post
Vector Databases Explained: Qdrant vs Weaviate vs Chroma (And Which One Won't Make You Cry)