← All articles
Abstract glitch art with digital code fragments

Grist: The Self-Hosted Spreadsheet That Thinks Like a Database

Productivity 2026-03-04 · 4 min read grist spreadsheet database airtable alternative self-hosted open-source python
By Selfhosted Guides Editorial TeamSelf-hosting practitioners covering open source software, home lab infrastructure, and data sovereignty.

Spreadsheets are easy to start but hard to maintain. Databases are powerful but require a developer. Grist sits in between: it has the familiar row-column interface of a spreadsheet, but it stores data in a relational model with proper references, computed columns, and access controls.

Photo by Egor Komarov on Unsplash

If you're running Airtable for internal tools and want to stop paying per seat, or you've outgrown Google Sheets but don't want to build a full app, Grist is worth evaluating.

What Makes Grist Different

Most spreadsheet alternatives add a UI skin over a database (Baserow, NocoDB). Grist goes the other direction — it starts with the spreadsheet mental model and adds database capabilities:

The result is something that non-technical users can understand while still handling the kind of data modeling that would normally require a developer.

Docker Deployment

services:
  grist:
    image: gristlabs/grist:latest
    container_name: grist
    environment:
      APP_HOME_URL: https://grist.yourdomain.com
      GRIST_SESSION_SECRET: your-random-secret-here
      # Optional: SMTP for invites
      GRIST_EMAIL_SENDER: [email protected]
      SMTP_HOST: smtp.yourdomain.com
      SMTP_PORT: 587
      SMTP_USER: [email protected]
      SMTP_PASSWORD: smtp-password
    volumes:
      - grist_data:/persist
    ports:
      - "8484:8484"
    restart: unless-stopped

volumes:
  grist_data:

Access the instance at http://localhost:8484. On first launch, create an admin account and then sign in.

For production, put Grist behind a reverse proxy (Nginx, Traefik, Caddy) with HTTPS. Set APP_HOME_URL to your public URL — Grist uses this for sharing and embed links.

Creating Your First Document

Grist organizes data into documents, each containing multiple tables. Think of a document as a database file and tables as, well, tables.

Example: Project Tracker

Create a document with two tables:

Projects table:

Column Type
Name Text
Status Choice (Active, Done, Paused)
Due Date Date
Owner Reference → People

People table:

Column Type
Name Text
Email Text
Team Text

The Owner column in Projects is a Reference to People. Grist enforces this relationship and lets you do lookups across tables in formulas.

Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.

Python Formulas

This is Grist's standout feature. Every computed column uses Python:

# Days until due date
from datetime import date
(rec.DueDate - date.today()).days

# Full name from first + last
rec.FirstName + " " + rec.LastName

# Sum of related records (like VLOOKUP, but cleaner)
sum(r.Hours for r in rec.Tasks.lookupRecords(Project=rec.id))

# Conditional
"Overdue" if rec.DueDate < date.today() and rec.Status != "Done" else rec.Status

Python gives you loops, list comprehensions, date arithmetic, and imports from the standard library. It's a real programming environment inside a spreadsheet.

Linked Views

Grist's killer feature for dashboards: linked sections. When you click a row in one table, other sections on the same page filter automatically.

A typical layout:

This creates a drill-down UI without writing any JavaScript. Non-technical users can navigate complex relational data through a well-designed page layout.

Access Rules

Grist has granular row-level and column-level permissions:

# Only show rows belonging to the current user
user.Email == rec.AssignedTo

# Hide salary column from non-managers
user.Role != "Manager"

# Allow editing only if status is Draft
rec.Status == "Draft"

Access rules run as filter conditions — not just UI controls, but enforced at the data layer. External embed viewers see only what the rules allow.

Grist vs. Alternatives

Feature Grist Airtable NocoDB Baserow
Self-hostable
Formulas Python Proprietary Limited Limited
Reference columns
Row-level permissions ✓ (paid) ✓ (paid)
Linked views
API access
Price (self-hosted) Free Free Free

NocoDB and Baserow are more database-forward — they connect to PostgreSQL/MySQL and manage tables there. Grist has its own storage model, which makes it simpler to set up but less flexible for existing database schemas.

REST API

Every Grist document has a REST API that external tools can use:

# List records in a table
curl -H "Authorization: Bearer YOUR-API-KEY" \
  "https://grist.yourdomain.com/api/docs/DOC_ID/tables/Projects/records"

# Create a record
curl -X POST -H "Authorization: Bearer YOUR-API-KEY" \
  -H "Content-Type: application/json" \
  -d '{"records":[{"fields":{"Name":"New Project","Status":"Active"}}]}' \
  "https://grist.yourdomain.com/api/docs/DOC_ID/tables/Projects/records"

This makes Grist useful as a lightweight data store for scripts and automation tools. Pair it with n8n or Pipedream for no-code integrations.

When to Use Grist

Grist shines for:

Skip Grist if you need to connect to an existing PostgreSQL database (use NocoDB or Baserow), or if you need real-time collaboration at Notion's scale.

Get free weekly tips in your inbox. Subscribe to Self-Hosted Weekly