teable Documentation

AI Spreadsheet for Business

RAW Doc

1. Project Overview & Quickstart (teableio/teable)

File: README.md

Quick Guide

  1. Want to see it in action? Try Teable on our hosted cloud at teable.ai.
  2. Deploying it yourself? Start from the Deployment guide — standalone in minutes, or the full AI platform on your own machines.

Four platforms in one

AI chat, App Builder, and app deployments are part of Teable, not bolt-ons.
Self-hosting Teable deploys four platforms in one:

  • A secure, scalable agent sandbox — every AI session runs in its own isolated container, started on demand and gone when the session ends.
  • A resource-efficient app deployment platform — every app your team builds and publishes runs as its own lightweight, long-lived container.
  • An AI workflow engine — automations triggered by record changes, schedules, and webhooks, with AI steps, running right where your data lives.
  • A full-featured database collaboration platform on PostgreSQL — tables, views, permissions, and API.

Self-hosting wraps your own compute into an agent-ready, fully controlled
productivity environment
— putting AI in the hands of everyone on your team.
See Architecture for how the
pieces fit together.

✨Features

🤖 AI-native

  • AI Chat — ask, analyze, and operate on your data in natural language.
  • App Builder — describe the app you need; an agent builds it in an isolated sandbox and deploys it to its own URL in one click.
  • AI automations — react to record changes, schedules, and webhooks, with AI steps doing the reasoning.
  • AI field filling — generate and enrich field values in bulk.

🍺 Everything you need, out of the box

Grid, Form, Kanban, Gallery, and Calendar views; formulas, field conversion,
filtering, grouping, sorting, and aggregation; comments, record history,
undo/redo, and real-time collaboration; attachments preview, batch editing,
import/export, search, validation, charts, plugins, SQL query — and millions
of rows without breaking a sweat.

More features land all the time — see the Changelog.

Deploy

Three ways to run Teable — pick by what you need (full comparison in the
Deployment guide):

Teable Cloud Full-featured self-host Standalone self-host
Tables, collaboration, API, automation ✅ ✅ ✅
AI features (chat, agents) ✅ ✅ ❌
App Builder (build & deploy apps) ✅ ✅ ❌
Start here teable.ai teableio/teable-deployment Docker guide

Prefer not to deploy by hand? Hand teableio/teable-deployment
to your AI agent
(Claude Code, Codex, …) together with a domain, a DNS token,
and access to the target machine or cluster — it can take the deployment end
to end.

Already running standalone Teable? The runtime plane installs next to it and
your data stays in place: migration guide.

Development

1. Initialize

sh
# Enabling the Help Management Package Manager
corepack enable

# Install project dependencies
pnpm install

2. Initialize Postgres

sh
make switch-db-mode

3. Custom Environment Variables(Optional)

sh
cd apps/nextjs-app
cp .env.development .env.development.local

4. Run Dev Server

you just need to start backend, it will start next server for frontend automatically, file change will be auto reload

sh
cd apps/nestjs-backend
pnpm dev

Why Teable?

Software should fit the work — not the other way around. Every team knows
the compromise: you have a concrete business need, you search for an app, and
it covers 70% of it. So you bend your process around the tool, or you file a
ticket and wait quarters for custom development. The work adapts to the
software, when it should be the software adapting to the work.

AI only changes this if it reaches the real workflow. A wave of AI tools
can now generate an app on demand — but each one is built in a vacuum: an
empty database, no knowledge of how your team actually operates, one more
island to integrate and maintain. The demo impresses; the workflow stays the
same.

Teable puts the agent where the work already happens. Your data, apps,
automations, permissions, and collaborators live here, on a real PostgreSQL —
and the AI operates all of it. Chat acts on live data. Automations reason
over records as they change. App Builder ships working systems wired to the
same database your team already uses — so what gets built is never another
silo, but a precise extension of the workflow it came from. AI lands in the
work seamlessly, and what it builds fits the business exactly.

And it's an architecture an IT team can say yes to. Self-hosting Teable
packages your own compute into an agent-ready platform for the whole team:
every AI session confined to an isolated sandbox, every app shipped as a
standard container, everything resting on PostgreSQL and HTTP APIs, with your
own models and keys, on your own infrastructure. Full AI capability, full
control — neither traded for the other.

The result is a different way of building: business systems shaped precisely
to your business, delivered in days instead of quarters, evolving as fast as
the work itself — by everyone on the team, not just the people who code.

License

This repository is the Teable Community Edition: free for self-hosting under
the AGPL-3.0 license (packages under packages/ are MIT). See
./LICENSE for details.

The official image ghcr.io/teableio/teable
ships the complete product: free to run, with paid plans unlocking AI features
and advanced enterprise capabilities in place — activate with a license
key, no image swap, no migration. See pricing and
subscribe & activate.


File: apps/nextjs-app/README.md

The web-app

You don't need start this app when developing locally, it's started by the nestjs-backend.

all env is maintained in the .env* file, it is shared with the backend.


File: apps/nestjs-backend/src/features/calculation/README.md

我有这样的一个数据结构定义,id 为 fieldId, dependency 是当前 field 所依赖的 field 的 id。
IFieldMap 包括了所有 field 对应的信息的 map

ts
interface ITopologicalItem {
  id: string;
  dependencies: string[];
}

interface IField {
  type: "other" | "link";
}

type IFieldMap = { [id: string]: IField };

一个 record 中的某个 field 变化了之后,就会触发相关的依赖计算。也就是说,我们提供一个 recordId 然后按照拓扑排序中的顺序,依次计算每个 field 的值。

link 字段在这里会导致 一个 record 变化,引发其他多个 record 变化的情况,比如

recordA1 和 recordA2 的 fieldY 都引用 recordB1 的 fieldX 的值,其中 fieldY 为 type 为 link 的字段

ts
recordA1[fieldBLinkB] = recordB1[fieldB];
recordA2[fieldBLinkB] = recordB1[fieldB];

那么,当 recordB1 的 fieldX 变化的时候,就会触发 recordA1 和 recordA2 的 fieldY 的变化。
也就是说,当传入 recordB1 的 id 进入拓扑排序遍历的时候,经过 fieldY 字段时,需要裂变成 recordA1、recordA2 两个 id,然后继续遍历计算

请问,我如何一次性查询出,从 recordB1 出发,最终会发生变化的 record, 以及他们与各自 field 之间的关系
简单场景
b1[fieldB] 变化
fieldB -> fieldLinkB

ts
[
  { id: "fieldB", dependencies: [], recordId: ["b1"] },
  { id: "fieldLinkB", dependencies: ["fieldB"], recordId: ["b1"], targetRecordId: ["a1", "a2"] }, // formula({fieldB})
];

link 字段的计算,是带入关联表中的 recordId 以及对应的 recordData 计算的,而计算后的值,将存入当前表的 targetRecordId 中对应的 link 字段下。

ts
[
  { id: "fieldB", dependencies: [], recordId: ["b1"] },
  { id: "fieldLinkB", dependencies: ["fieldB"], recordId: ["b1"], targetRecordId: ["a1", "a2"] },
  { id: "fieldA", dependencies: ["fieldLinkB"], recordId: ["a1", "a2"] },
  { id: "fieldLinkA", dependencies: ["fieldA"], recordId: ["a1", "a2"], targetRecordId: ["b1"] },
];

fieldA -> FieldLinkA -> formula。
拓扑排序只包含从变更入口开始的有向图

ts
[
  { id: "fieldA", dependencies: [], recordId: ["a1"] },
  // { id: "fieldC", dependencies: [] },
  { id: "FieldLinkA", dependencies: ["fieldA"], recordId: ["a1", "a2"], targetRecordId: ["b1"] },
  // { id: "FieldLinkC", dependencies: ['fieldC'], recordId: ['c1', 'c2'], targetRecordId: ['b1'] },
  { id: "formula", dependencies: ["FieldLinkA", "FieldLinkC"] },
];

单次找出所有 recordId

我有以下数据结构, 这是一组拓扑排序后的数据结果。代表着 fieldA -> fieldLinkA -> fieldLinkB 这样的一张有向无环图关系。
tableName 代表表名称
fieldName 代表字段名称
targetLinkField 代表外键的字段名称,该字段存储了关联的 record
linkedTable 代表了这个 targetLinkField 关联的表名称
dependencies 代表关联后,他们需要查询 record 中哪个 field 的值

ts
const topologicalOrder = [
  { tableName: "A", fieldName: "fieldA", dependencies: [] },
  {
    tableName: "B",
    fieldName: "fieldLinkA",
    targetLinkField: "__fk_fieldLinkA",
    linkedTable: "A",
    dependencies: ["fieldA"],
  },
  {
    tableName: "C",
    fieldName: "fieldLinkB",
    targetLinkField: "__fk_fieldLinkB",
    linkedTable: "B",
    dependencies: ["fieldLinkA"],
  },
];

table 中的 record 数据用 json 表达如下
A 表

ts
[
  { id: "idA1", fieldA: "A1" },
  { id: "idA2", fieldA: "A2" },
];

B 表

ts
[
  { id: "idB1", fieldB: "B1", fieldLinkA: "A1", __fk_fieldLinkA: "idA1" },
  { id: "idB2", fieldB: "B2", fieldLinkA: "A1", __fk_fieldLinkA: "idA1" },
];

C 表

ts
[
  { id: "idC1", fieldC: "C1", fieldLinkB: "A1", __fk_fieldLinkB: "idB1" },
  { id: "idC2", fieldC: "C2", fieldLinkB: "A1", __fk_fieldLinkB: "idB1" },
  { id: "idC3", fieldC: "C3", fieldLinkB: "A1", __fk_fieldLinkB: "idB2" },
];

根据上述表述,如果 'idA1' 中的 fieldA 发生了变化,既可以推导出 ['idB1', 'idB2'] 和 ['idC1', 'idC2', 'idC3'] 都会受到关联关系的影响发生变化

我如何通过 SQL 一次性查找出这些 recordId 呢? 为了实现动态的查询需求,我会将 idA1 和 topologicalOrder 作为参数传入

一对多关系,反向引用计算链

A 表

ts
{ __id: 'idA1', fieldA: 'A1', oneToManyB: ['C1,C2', 'C3'] }

B 表

ts
{ __id: 'idB1', fieldB: 'C1,C2', manyToOneA: 'A1', __fk_manyToOneA: 'idA1', oneToManyC: ['C1', 'C2'] }
{ __id: 'idB2', fieldB: 'C3', manyToOneA: 'A1', __fk_manyToOneA: 'idA1', oneToManyC: ['C3'] }

C 表

ts
{ __id: 'idC1', fieldC: 'C1', manyToOneB: 'C1,C2', __fk_manyToOneB: 'idB1' },
{ __id: 'idC2', fieldC: 'C2', manyToOneB: 'C1,C2', __fk_manyToOneB: 'idB1' },
{ __id: 'idC3', fieldC: 'C3', manyToOneB: 'C3', __fk_manyToOneB: 'idB2' },

引用关系拓扑排序

ts
const topoOrder = [
  {
    dbTableName: "B",
    fieldName: "oneToManyC",
    foreignKeyField: "__fk_manyToOneB",
    relationship: Relationship.OneMany,
    linkedTable: "C",
  },
  {
    dbTableName: "A",
    fieldName: "oneToManyB",
    foreignKeyField: "__fk_manyToOneA",
    relationship: Relationship.OneMany,
    linkedTable: "B",
  },
  {
    dbTableName: "C",
    fieldName: "manyToOneB",
    foreignKeyField: "__fk_manyToOneB",
    relationship: Relationship.ManyOne,
    linkedTable: "B",
  },
];

我们看到。
A 表中的 idA1.oneToManyB: ['C1,C2', 'C3'] 的值,是从 C 表中id 为 'idB1', 'idB2' 对应的 fieldB 字段中得到,并形成数组的。
同理:
B 表中
idB1.oneToManyC: ['C1', 'C2'] 的值,是从 C 表中
id 为 'idC1', 'idC2' 对应的 fieldC 字段中得到,并形成数组的。
idB2.oneToManyC: ['C3'] 的值,是从 C 表中id 为 'idC3' 对应的 fieldC 字段中得到,并形成数组的。
C 表中
idC1.manyToOneB: 'C1,C2' 的值,是从 B 表中
id 为 'idB1' 对应的 fieldB 字段中引用得到。
idC2.manyToOneB: 'C1,C2' 的值,是从 B 表中__id 为 'idB1' 对应的 fieldB 字段中引用得到。

问题 1

C.idC1.fieldC 的值发生了变化,从 C1 变成了 C11, 怎么更新 A 表和 B 表的对应值?
首先我们用循环遍历的代码来实现,先定义一下最终的输出结构,者个结构由后续参与计算的时候,如何进行多值 lookup 合并来决定。
什么是多值 lookup 呢? 比如 B.oneToManyC 的值是 ['C1', 'C2'],那么我们需要从 C 表中找到 __id 为 'idC1', 'idC2' 的记录,然后将他们的 fieldC 字段的值合并成一个数组,最终得到 ['C1', 'C2']。

问题 2

假设,我们现在 A.oneToManyB 以及 B.oneToManyC 中的值都为空。我们怎么通过 topoOrder 中给出的关系,利用 SQL 查询加上 ts 计算,得到他们的值呢?


File: apps/nestjs-backend/README.md

NestJS backend for teable

TODO:
remove @valibot/to-json-schema in ai-sdk6
remove effect in ai-sdk6
remove @ai-sdk/provider-utils in ai-sdk6


File: dockers/examples/standalone/README.md

Example with teable standalone

Standalone runs the Teable core: tables, collaboration, API and automation.
For the AI features (chat, App Builder, sandboxes) use the
full-featured self-host deployment --
and if you are already running standalone, your data stays in place when
upgrading.

Look into the .env file and update the vaiables before executing docker compose up -d.

Teable

  • Accessible via http://127.0.0.1:3000
  • Uses postgres db for storage
  • Telemetry is disabled

File: dockers/examples/docker-swarm/README.md

Teable Deployment with Docker Swarm

This guide provides step-by-step instructions on how to deploy Teable using Docker Swarm, including initializing the
swarm, deploying services, and managing updates and service removal.

Initialization

First, initialize your Docker Swarm environment:

shell
docker swarm init
# Or specify the advertise address manually if needed:
# docker swarm init --advertise-addr 192.168.99.100

Deploying Services

Use the provided deploy.sh script to deploy your services. You can specify the service type and stack name as
arguments:

shell
# Syntax: ./deploy.sh [service_type] [stack_name]
./deploy.sh - example

# To view the current services:
docker service ls

# To deploy and configure updates for your application:
./deploy.sh app example

Managing Services

Removing a Service

To remove a deployed service, use the following command:

shell
docker stack rm example

Rolling Updates

For rolling updates of the application, forcing a re-deployment of the current configuration:

shell
docker service update --force example_teable

Additional Notes

Cleaning Up Shutdown Containers

To clean up containers that are in a shutdown state:

shell
docker rm $(docker stack ps --no-trunc -f "desired-state=shutdown" --format "{{.Name}}.{{.ID}}" example)

This guide outlines the basic steps for deploying and managing your Teable application with Docker Swarm, including
service deployment, updates, and cleanup procedures.


File: dockers/examples/cluster/README.md

Setup Instructions for Teable Cluster

Before executing docker compose up -d, ensure to update the variables in the .env file according to your
environment's requirements.

Teable Configuration

  • Access URL: Access the Teable interface via http://127.0.0.1:80.
  • Database Storage: Utilizes PostgreSQL database for data storage.
  • Telemetry: Telemetry collection is disabled by default.

MinIO Endpoint Configuration

When configuring the Teable cluster to use MinIO for storage, it's necessary to replace the
placeholder <MINIO_ENDPOINT> in the .env file with the appropriate endpoint:

  • For Intranet Use: Replace <MINIO_ENDPOINT> with the IP address of the host where MinIO is deployed. This setup
    is recommended if MinIO and Teable are on the same network.

  • For Extranet Use: Replace <MINIO_ENDPOINT> with the domain name or extranet IP address of your MinIO instance.
    Use this configuration if you need to access MinIO from outside your local network.

Public Database Proxy Configuration

To ensure smooth native database connections, you need to set the PUBLIC_DATABASE_PROXY variable in the .env file to
its default value, 127.0.0.1:42345. This port should match the port specified for the teable-db container in
the docker-compose.yaml file's ports attribute and can be adjusted to suit your needs.

Important Note: When using ports 80 or 443, it's essential to explicitly specify the port number in the URL.
Failing to do so is not allowed. This practice guarantees accurate address resolution and dependable connectivity,
providing a solid foundation for your database connections.

Ensure to review and adjust these configurations to match your deployment environment before starting the Teable
cluster.

2. Official Technical Reference & Guides (teableio/teable-docs)

Teable Help

Development

Install the Mintlify CLI to preview the documentation changes locally. To install, use the following command

text
npm i mintlify

Run the following command at the root of your documentation (where docs.json is)

text
mintlify dev

Paste Image

Use the Paste Image extension to paste images into the markdown file.
Open mdx file and press cmd + option + v to paste image.

Image Assets

Images are shared repo assets. Keep paths stable, names searchable, and
rendering consistent.

When a change includes images, ask the agent to read this section first and
commit only images processed according to these rules.

Folder Rules

  • Use images/{top-level-group}/{topic}/.
  • Top-level groups: docs, selfhosted, api, security, changelog.
  • docs maps to the Help Center Docs tab. Do not flatten
    images/docs/{topic}/ into images/{topic}/.
  • {topic} maps to the navigation name in docs.json, such as ai, base,
    space, sso, authority-matrix, get-id, sql-query, or activate.
  • Do not put new screenshots in the images/ root.
  • Do not commit random staging folders.
  • Put unreferenced images in images/orphans/YYYY-MM-DD/... first. Do not
    delete them directly.
  • Docs pages must not reference images/orphans/....

Naming

Use this format:

text
images/{top-level-group}/{topic}/YYYY-MM-DD-page-slug-purpose.png
images/{top-level-group}/{topic}/YYYY-MM-DD-page-slug-purpose.webp
images/{top-level-group}/{topic}/YYYY-MM-DD-page-slug-purpose-zh.png
  • Date = day the image enters the docs repo.
  • Page slug = docs page or feature area.
  • Purpose = visible UI or action. Do not use image1 or random hashes.
  • Use .png for static UI screenshots.
  • Prefer .webp for animated screenshots.
  • English-only screenshot = shared asset. Do not add -en.
  • Chinese-specific screenshot = add -zh.

Image Handling

  • Logos, inline icons, external button images, videos, and historical changelog
    media do not need screenshot styling.

MDX Usage

Use explicit `` for docs screenshots:

mdx
  • Use className="docs-screenshot" for new PNG/WebP docs screenshots under
    images/docs/, images/api/, images/selfhosted/, and images/security/.
  • Alt text must be non-empty.
  • Alt text describes the visible UI or action. Do not use screenshot or the
    file name.
  • Do not use `` for new docs screenshots.
  • Avoid width="400", percentage widths, and one-off image sizing.
  • Changelog images keep their historical display. Add useful alt text when
    context exists. Do not add docs-screenshot blindly.

Publishing Changes

Push to origin main branch, the changes will be deployed to production automatically.

Troubleshooting

  • Mintlify dev isn't running - Run mintlify install it'll re-install dependencies.
  • Page loads as a 404 - Make sure you are running in a folder with docs.json