How to Self-Host Grist with Docker Compose
What Is Grist?
Grist is an open-source spreadsheet-database hybrid that combines the flexibility of spreadsheets with the structure of a relational database. It uses full Python for formulas instead of Excel syntax, stores everything in portable SQLite files, and provides granular access controls down to the row and column level. Think Airtable, but self-hosted with no per-seat pricing.
Updated March 2026: Verified with latest Docker images and configurations.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 1 GB of free RAM (2 GB recommended)
- 2 GB of free disk space plus storage for documents
- A domain name (optional, for remote access)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
grist:
image: gristlabs/grist:1.7.11
container_name: grist
restart: unless-stopped
ports:
- "8484:8484"
environment:
# Admin email — first user with this email becomes admin
- GRIST_DEFAULT_EMAIL=${GRIST_ADMIN_EMAIL}
# Session encryption key — generate with: openssl rand -hex 32
- GRIST_SESSION_SECRET=${GRIST_SESSION_SECRET}
# Require login for all access
- GRIST_FORCE_LOGIN=true
# Enable Python formula sandboxing (recommended)
- GRIST_SANDBOX_FLAVOR=gvisor
# Boot diagnostics key — generate with: openssl rand -hex 16
- GRIST_BOOT_KEY=${GRIST_BOOT_KEY}
# Optional: set default locale
- GRIST_DEFAULT_LOCALE=en
volumes:
- grist_data:/persist
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8484"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
volumes:
grist_data:
Create a .env file alongside:
# Admin email — this user gets owner access
GRIST_ADMIN_EMAIL=[email protected]
# Session secret — generate with: openssl rand -hex 32
GRIST_SESSION_SECRET=CHANGE_ME_TO_RANDOM_64_CHAR_HEX
# Boot key for /admin diagnostics — generate with: openssl rand -hex 16
GRIST_BOOT_KEY=CHANGE_ME_TO_RANDOM_32_CHAR_HEX
Start the stack:
docker compose up -d
Initial Setup
- Navigate to
http://your-server:8484 - Sign in with the email address you set in
GRIST_ADMIN_EMAIL - You’ll land on your personal workspace — create your first document
- Access the admin panel at
http://your-server:8484/adminusing your boot key
Grist uses email-based authentication by default. The first user who signs in with the configured admin email gets full owner permissions.
Configuration
PostgreSQL Backend (Production)
For multi-user deployments, replace the built-in SQLite with PostgreSQL:
services:
grist:
image: gristlabs/grist:1.7.11
container_name: grist
restart: unless-stopped
ports:
- "8484:8484"
environment:
- GRIST_DEFAULT_EMAIL=${GRIST_ADMIN_EMAIL}
- GRIST_SESSION_SECRET=${GRIST_SESSION_SECRET}
- GRIST_FORCE_LOGIN=true
- GRIST_SANDBOX_FLAVOR=gvisor
- GRIST_BOOT_KEY=${GRIST_BOOT_KEY}
- TYPEORM_TYPE=postgres
- TYPEORM_HOST=grist-db
- TYPEORM_PORT=5432
- TYPEORM_DATABASE=grist
- TYPEORM_USERNAME=grist
- TYPEORM_PASSWORD=${DB_PASSWORD}
volumes:
- grist_data:/persist
depends_on:
grist-db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8484"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
grist-db:
image: postgres:16-alpine
container_name: grist-db
restart: unless-stopped
environment:
- POSTGRES_USER=grist
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=grist
volumes:
- grist_db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U grist"]
interval: 10s
timeout: 5s
retries: 5
volumes:
grist_data:
grist_db:
Key Environment Variables
| Variable | Purpose | Default |
|---|---|---|
GRIST_DEFAULT_EMAIL | Admin user email | [email protected] |
GRIST_FORCE_LOGIN | Require authentication | false |
GRIST_SESSION_SECRET | Cookie encryption key | Auto-generated |
GRIST_SANDBOX_FLAVOR | Python formula sandboxing | unsandboxed |
GRIST_MAX_UPLOAD_IMPORT_MB | Max import file size | 64 |
GRIST_MAX_UPLOAD_ATTACHMENT_MB | Max attachment size | 64 |
GRIST_ORG_CREATION_ANYONE | Allow any user to create orgs | false |
Advanced Configuration (Optional)
OIDC Authentication
Connect Grist to your existing SSO provider:
environment:
- GRIST_OIDC_IDP_ISSUER=https://auth.example.com
- GRIST_OIDC_IDP_CLIENT_ID=grist
- GRIST_OIDC_IDP_CLIENT_SECRET=${OIDC_SECRET}
- GRIST_OIDC_IDP_SCOPES=openid email profile
S3-Compatible Storage
Store documents in MinIO or S3 instead of the local filesystem:
environment:
- GRIST_DOCS_S3_BUCKET=grist-docs
- GRIST_DOCS_S3_ACCESS_KEY=${S3_ACCESS_KEY}
- GRIST_DOCS_S3_SECRET_KEY=${S3_SECRET_KEY}
- GRIST_DOCS_S3_ENDPOINT=http://minio:9000
Reverse Proxy
Grist runs on port 8484. Configure your reverse proxy to forward traffic:
Nginx Proxy Manager: Point your domain to http://grist:8484 with WebSocket support enabled.
For detailed setup, see Reverse Proxy Setup.
Backup
Back up the /persist volume, which contains all documents and configuration:
docker compose stop grist
tar -czf grist-backup-$(date +%Y%m%d).tar.gz /path/to/grist_data
docker compose start grist
If using PostgreSQL, also dump the database:
docker exec grist-db pg_dump -U grist grist > grist-db-backup.sql
For a comprehensive backup strategy, see Backup Strategy.
Troubleshooting
Documents Load Slowly
Symptom: Large documents take 10+ seconds to open. Fix: Grist loads the entire document into memory. Reduce document size by splitting large datasets across multiple documents, or increase container RAM.
Python Formulas Not Working
Symptom: Formula errors mentioning sandbox or Python.
Fix: Ensure GRIST_SANDBOX_FLAVOR=gvisor is set. If running on ARM (Raspberry Pi), gvisor isn’t supported — use GRIST_SANDBOX_FLAVOR=unsandboxed and restrict document access to trusted users.
Permission Denied on /persist
Symptom: Container exits with permission errors.
Fix: Grist runs as UID 1000 by default. Set ownership: chown -R 1000:1000 /path/to/grist_data.
Admin Panel Shows “Boot Key Required”
Symptom: Cannot access /admin endpoint.
Fix: Set the GRIST_BOOT_KEY environment variable and append ?boot-key=YOUR_KEY to the admin URL.
Resource Requirements
- RAM: 200 MB idle, 500 MB–1 GB under active use (scales with document size)
- CPU: Low — 1 core sufficient for small teams, 2 cores recommended
- Disk: 200 MB for the application, plus storage proportional to your documents
Verdict
Grist is the best self-hosted Airtable alternative for teams that need Python formula power and granular access controls. The database-spreadsheet hybrid model works well for structured data that needs computed views — project trackers, inventory systems, CRM-like workflows. It’s significantly more capable than a plain spreadsheet but lighter than a full low-code platform like NocoDB or Baserow. If you just need collaborative document editing, look at CryptPad or OnlyOffice instead.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments