Airtable is wonderful until it is not. Then you hit the row limit, the API rate cap, the per-seat pricing cliff — and realise that all your data lives somewhere you cannot easily leave. Teable was built to fix that. It looks like a spreadsheet, behaves like a database, runs on your own server, and does not flinch at a million rows.
What is Teable?
Teable is an open-source no-code database platform with a spreadsheet-style interface. Teams use it to manage projects, track inventory, build internal tools, collect form data, and collaborate in real time — without writing a single line of SQL.
“Teable uses a simple, spreadsheet-like interface to create powerful database applications. Collaborate with your team in real-time, and scale to millions of rows.”
The key architectural decision that sets it apart: your data lives in real PostgreSQL tables. Not a custom binary format, not a JSON blob column — actual relational tables you can query directly with any SQL tool.
Teable Source Code on GitHub Teable Documentation Template Gallery
Why teams choose Teable
- 📊 Real-time collaboration — multiple users edit simultaneously with Operational Transformation (the same tech as Google Docs), no last-write-wins conflicts
- 🚀 Millions of rows — a WebGL-accelerated virtualised grid keeps scrolling smooth at any scale
- 🐘 Real PostgreSQL — your data is in actual PG tables; query it with psql, Metabase, or any BI tool
- 🔌 Five view types — Grid, Kanban, Gallery, Form, Calendar
- 🧩 Plugin system — extend with custom views and panels via an iframe SDK
- 📤 Import / Export — CSV, Excel, direct SQL access via exposed PG proxy port
- 🔐 Self-hosted, AGPL-3.0 — full data sovereignty, no per-row or per-seat limits you do not set yourself
- 🌐 i18n — translations managed via Crowdin, multiple languages out of the box
Teable Tech Overview
Teable is a pnpm monorepo with a clear separation between a Next.js frontend and a NestJS backend — two apps, six shared packages.
Frontend — Next.js + Glide Data Grid
The web app is built with Next.js 16 and React 18. The star component is Glide Data Grid — a WebGL-rendered spreadsheet that virtualises both rows and columns, which is why 1,000,000-row tables feel like 100-row tables. TanStack Query handles server state; Zustand handles client UI state; FullCalendar powers the Calendar view; ECharts handles charts.
Real-time cell updates arrive over WebSocket via the ShareDB client — the same connection the backend uses to synchronise edits between users.
Backend — NestJS + Prisma + ShareDB
The NestJS server uses two ORM strategies:
- Prisma manages the system schema — users, spaces, bases, permissions, metadata — via declarative migrations.
- Kysely + Knex build dynamic SQL queries at runtime for user-defined tables, where the schema changes as users add fields and rows.
ShareDB runs the Operational Transformation engine that makes real-time collaboration work. When two users edit the same cell, OT ensures both edits are applied correctly instead of one overwriting the other.
BullMQ + Redis handle background jobs: formula recalculation, rollup updates, attachment processing, and email sending.
Field types
Teable supports a full range of column types: Text, Number, Date, Checkbox, Single/Multi Select, Attachments, Link (cross-table relationships), Formula, Lookup, Rollup, Rating, Currency, User, Auto Number, and more.
The Formula engine (in packages/formula) evaluates spreadsheet-style expressions with functions for string manipulation, date arithmetic, logical operations, and aggregates across linked records.
Self-Hosting Teable with Docker
Get Docker 🐋
Install Docker on your system before proceeding:
- Linux: Official Docker Engine install guide
- Windows / Mac: Docker Desktop
Verify installation: docker --version && docker compose version
Teable ships a clean standalone compose file. Three services, five minutes to running.
services:
teable:
image: ghcr.io/teableio/teable:latest
restart: always
ports:
- '3000:3000'
volumes:
- teable-data:/app/.assets
env_file:
- .env
environment:
- TZ=${TIMEZONE}
networks:
- teable-standalone
depends_on:
teable-db:
condition: service_healthy
teable-cache:
condition: service_healthy
teable-db:
image: postgres:15.4
restart: always
ports:
- '42345:5432' # exposes PG for direct SQL access
volumes:
- teable-db:/var/lib/postgresql/data
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
networks:
- teable-standalone
healthcheck:
test: ['CMD-SHELL', "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 3s
retries: 3
teable-cache:
image: redis:7.2.4
restart: always
volumes:
- teable-cache:/data
networks:
- teable-standalone
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
healthcheck:
test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping']
interval: 10s
timeout: 3s
retries: 3
networks:
teable-standalone:
driver: bridge
volumes:
teable-data: {}
teable-db: {}
teable-cache: {}
Pair this with a .env file:
TIMEZONE=UTC
POSTGRES_DB=teable
POSTGRES_USER=teable
POSTGRES_PASSWORD=change_this_password
REDIS_PASSWORD=change_this_too
PUBLIC_ORIGIN=http://your-server-ip:3000
SECRET_KEY=a_long_random_string_change_this
PRISMA_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@teable-db:5432/${POSTGRES_DB}
PUBLIC_DATABASE_PROXY=your-server-ip:42345
BACKEND_CACHE_PROVIDER=redis
BACKEND_CACHE_REDIS_URI=redis://default:${REDIS_PASSWORD}@teable-cache:6379/0
Then:
docker compose up -d
Open http://your-server-ip:3000. The first account created becomes the admin.
Default credentials: None — you create the admin account on first load.
Services explained
| Service | Purpose |
|---|---|
teable |
The full application — Next.js frontend + NestJS backend in one image |
teable-db |
PostgreSQL 15 — stores all user data in real relational tables |
teable-cache |
Redis 7 — session cache, job queue, real-time state |
Port 42345 maps to PostgreSQL. This is intentional — it lets you connect any SQL client (psql, DBeaver, Metabase) directly to your Teable data without any API layer.
Adding S3 or MinIO for file attachments
By default, attachments are stored locally in the /app/.assets volume. For production, use MinIO or S3:
# MinIO (self-hosted S3-compatible)
BACKEND_STORAGE_PROVIDER=minio
BACKEND_STORAGE_PUBLIC_BUCKET=teable-public
BACKEND_STORAGE_PRIVATE_BUCKET=teable-private
BACKEND_STORAGE_MINIO_ENDPOINT=minio.yourdomain.com
BACKEND_STORAGE_MINIO_PORT=443
BACKEND_STORAGE_MINIO_USE_SSL=true
BACKEND_STORAGE_MINIO_ACCESS_KEY=your_access_key
BACKEND_STORAGE_MINIO_SECRET_KEY=your_secret_key
STORAGE_PREFIX=https://minio.yourdomain.com
# AWS S3
BACKEND_STORAGE_PROVIDER=s3
BACKEND_STORAGE_S3_REGION=us-east-1
BACKEND_STORAGE_S3_ENDPOINT=https://s3.us-east-1.amazonaws.com
BACKEND_STORAGE_S3_ACCESS_KEY=AKIA...
BACKEND_STORAGE_S3_SECRET_KEY=your_secret
BACKEND_STORAGE_PUBLIC_BUCKET=teable-public
BACKEND_STORAGE_PRIVATE_BUCKET=teable-private
Enabling OAuth login (GitHub / Google / OIDC)
Add these to your .env:
# GitHub OAuth
BACKEND_GITHUB_CLIENT_ID=your_github_client_id
BACKEND_GITHUB_CLIENT_SECRET=your_github_secret
BACKEND_GITHUB_CALLBACK_URL=https://teable.yourdomain.com/api/auth/github/callback
# Google OAuth
BACKEND_GOOGLE_CLIENT_ID=your_google_client_id
BACKEND_GOOGLE_CLIENT_SECRET=your_google_secret
BACKEND_GOOGLE_CALLBACK_URL=https://teable.yourdomain.com/api/auth/google/callback
# Enable the providers
SOCIAL_AUTH_PROVIDERS=github,google
For SSO via any OIDC provider (Keycloak, Authentik, etc.):
BACKEND_OIDC_CLIENT_ID=...
BACKEND_OIDC_CLIENT_SECRET=...
BACKEND_OIDC_CALLBACK_URL=https://teable.yourdomain.com/api/auth/oidc/callback
BACKEND_OIDC_AUTHORIZATION_URL=https://sso.yourdomain.com/auth
BACKEND_OIDC_TOKEN_URL=https://sso.yourdomain.com/token
BACKEND_OIDC_USER_INFO_URL=https://sso.yourdomain.com/userinfo
BACKEND_OIDC_ISSUER=https://sso.yourdomain.com
SOCIAL_AUTH_PROVIDERS=oidc
Conclusion
Teable occupies exactly the right spot in the no-code landscape: powerful enough for real data workflows, simple enough that non-developers can use it immediately, and built on standard PostgreSQL so you are never locked in.
The real-time collaborative editing via Operational Transformation, the WebGL grid that handles a million rows without slowing down, and the clean three-container Docker setup make it one of the most production-ready Airtable alternatives you can self-host today.
Alternatives worth comparing:
- NocoDB — similar goal, stores data in its own format rather than native PG tables; easier initial setup
- Baserow — Python/Django backend, strong plugin ecosystem, FOSS community edition
- Grist — spreadsheet-database hybrid, Python formulas, unique dataflow model
- Airtable — the original; excellent UX, cloud-only, per-seat pricing
Frequently Asked Questions
Can I query my Teable data with SQL?
Yes — that is a core design feature. Port 42345 exposes PostgreSQL directly. Connect with psql, DBeaver, Metabase, or any BI tool using the credentials in your .env. Your tables and columns map 1:1 to what you see in the UI.
How many rows can it actually handle?
The hosted demo runs at 1,000,000 rows. Performance depends on your PostgreSQL instance — Teable itself adds minimal overhead thanks to the virtualised grid renderer. Index your filter columns and you will have no issues at that scale.
Is there a row or user limit in the self-hosted Community Edition?
No hard row limit (you can set MAX_FREE_ROW_LIMIT if you want one). No per-seat limit. You control the constraints.
What is the difference between CE and Enterprise Edition?
CE (AGPL) includes all base features: all views, real-time, formulas, attachments, plugins, API, OAuth. EE adds AI features, advanced authority matrix (field-level permissions), advanced automations, and an admin panel. EE requires a commercial licence.
Does it support email invitations and notifications?
Yes, configure BACKEND_MAIL_* env vars with your SMTP server (Gmail, Resend, Mailgun, or self-hosted Postfix). Without it, user invitations still work but send no email — users must be added manually.
Can I put it behind a reverse proxy?
Yes. Set PUBLIC_ORIGIN to your full domain (e.g., https://teable.yourdomain.com) and proxy port 3000. Teable handles its own WebSocket upgrade on the same port, so no separate WebSocket proxy config is needed.
Comments