Every few months a client tells us they have "outgrown Airtable". Roughly half the time they have not: they have a data model problem, a rollup problem, or a 40,000-record grid view that nobody needed to look at. The other half genuinely have hit a structural ceiling, and the right answer is to move the system of record somewhere else while keeping the parts of Airtable that people actually love.
This guide is the triage we run before anyone signs off on a migration, plus the staged pattern we use when migration is the right call.
The five symptoms that actually mean something
Be specific about the pain. "Airtable is slow" is not a reason to rebuild a business system. These are:
1. Record volume against per-table limits. Airtable enforces per-base record ceilings by plan, and even well under the ceiling, tables in the hundreds of thousands of records make interfaces, filters, and rollups sluggish. If a single table grows by tens of thousands of rows a month forever — event logs, telemetry, transaction lines, scraped data — you are on a curve that no amount of tuning flattens.
2. Write concurrency and race conditions. Airtable has no transactions. If two automations, or an automation and a human, can touch the same record in the same second, you will eventually get lost updates, double-created linked records, or two invoices numbered INV-1043. You can mitigate with queue tables and idempotency keys, but if correctness of money or inventory depends on it, that is a database-level guarantee you cannot buy back.
3. API rate limits in the critical path. Five requests per second per base is generous for internal ops and hopeless as the backing store for a customer-facing app or a high-frequency integration. If real users are waiting on your Airtable reads, you have outgrown it.
4. Query shapes Airtable cannot express. Multi-table joins, window functions, "revenue by cohort by month with a 90-day trailing average", point-in-time reporting. Formulas and rollups are per-record, not set-based. Piling helper fields on to fake a GROUP BY is the classic sign.
5. Cost curve driven by seats, not value. When the number of people who must edit data grows faster than the number who create value in the base, per-seat pricing turns against you. Read-only consumers can often be served by interfaces or a BI tool instead — see our Airtable seats, plans, and credits cost audit before you conclude this one.
Notice what is not on the list: "the base is messy", "automations keep breaking", "reporting is painful", "onboarding new staff takes ages". Those are design problems, and they follow you to Postgres.
Fixes that buy you two more years
Run these before costing a migration. In our experience they resolve most "we need a real database" conversations.
- Archive cold data out of the hot table. Keep the last 12–18 months in the working table; push older records to an archive base or to object storage plus a warehouse. Most operational tables are 90% cold.
- Split by lifecycle, not by entity. A single
Jobstable holding quotes, live jobs, and closed jobs for six years will always be slow. Three tables with a sync between them will not. - Kill the wide views. Grid views with 60 fields, six rollups, and no filter are the single biggest cause of perceived slowness. Give each role a narrow, filtered view. Our performance tuning guide goes field by field.
- Move aggregation out of formulas. Nightly scripted rollups that write a single number beat live rollup chains across three linked tables.
- Fix the data model. Junction tables where you have many-to-many, no circular lookups, no "one table to rule them all". See linked records and junction tables.
- Serialise the writers. One automation owning each field, a queue table for bursts, idempotency keys so retries are safe.
If you do all six and still hit the symptoms above, the ceiling is real.
The pattern we actually recommend: Airtable as the front end
The binary framing — stay on Airtable or rebuild everything — is the expensive one. The useful question is which layer moves.
Most operational systems have three layers: the system of record, the workflow logic, and the human interface. Airtable is excellent at the third, decent at the second, and the first is what breaks. So move the first.
Before: people -> Airtable (UI + logic + data)
After: people -> Airtable Interfaces (UI)
|
v
sync/API layer (jobs, webhooks)
|
v
Postgres (system of record, history, reporting)
Three concrete shapes of this:
Shape A — Airtable stays operational, Postgres becomes the warehouse. A scheduled extract copies Airtable tables into Postgres; all reporting, history, and heavy queries run there. Airtable stays under the volume that keeps it fast because you can now archive aggressively without losing history. Cheapest option, fixes symptoms 1, 4, and often 5. Does nothing for 2 and 3.
Shape B — Postgres owns one hot entity; Airtable keeps the rest. The 400,000-row transaction log lives in Postgres. Airtable holds customers, jobs, and staff, and shows summarised transaction data per record via a synced or scripted rollback of aggregates. This is the highest-value, lowest-drama move for the common case where exactly one table is the problem.
Shape C — Postgres is the system of record; Airtable is a view. Postgres holds everything and enforces constraints; a sync layer mirrors a working subset into Airtable for the humans, and writes flow back through an API that Postgres validates. Solves all five symptoms and costs the most. Justify it with symptom 2 or 3, not with tidiness.
Staging a migration without a big-bang cutover
- Freeze the schema and document it. Export field names, types, options, formulas, and link relationships to a spreadsheet. You cannot map what you have not written down. (Scripting extension plus the metadata API will do this for you.)
- Model it properly in Postgres. Do not translate Airtable one-to-one. Linked record fields become foreign keys or join tables; single selects become enums or lookup tables; attachments become object-storage keys with the file copied out, because Airtable attachment URLs expire — see attachments at scale.
- Build a one-way extract first. Paginated reads via the REST API into staging tables, upserting on the Airtable record ID, which becomes your durable external key. Run it nightly for two weeks and diff the results. This alone delivers Shape A.
- Reconcile. Row counts per table, sums of every numeric column, spot-check 20 records end to end, and a report of rows that failed type conversion. Do not proceed while that report is non-empty.
- Pick the write path. For Shape B or C, decide exactly one owner per field and write it down. Bidirectional sync without a declared owner produces flapping records and is the most common way these projects fail. Webhooks push Airtable changes into your sync layer in near real time — Airtable webhooks covers the mechanics.
- Cut over one workflow at a time. Start with something read-mostly and non-urgent — reporting, then a low-stakes approval — and keep Airtable authoritative for the rest until each one has run a full cycle.
- Keep a rollback. Until the last workflow has moved, the nightly Airtable snapshot is your undo button. Our backup and disaster recovery guide is the baseline.
Costs people forget to budget
- The sync layer is a product. It needs logging, retries, alerting, and an owner. Budget for running it, not just building it.
- Permissions get harder. Airtable's sharing model disappears; row-level security, roles, and auditing all become your job.
- Someone must rebuild the interfaces. If you move to Shape C and do not keep Airtable as the UI, you are now funding front-end work forever. This is the line item that sinks most "let's just use a real database" plans.
- Staff retraining and a period of double entry. Assume some overlap. Plan for it explicitly rather than pretending the cutover is instant.
A decision table you can use in a meeting
| Situation | Do this |
|---|---|
| Slow base, under ~50k rows per table | Tune views, model, and rollups. Stay. |
| One table growing without bound | Shape B: move that table out. |
| Reporting and history are the only pain | Shape A: extract to Postgres/warehouse. |
| Customer-facing app reads live data | Shape C, or a cache in front of Postgres. |
| Money or stock correctness at risk from concurrent writes | Shape C. Do not negotiate. |
| "It feels unprofessional" | Not a reason. Fix the model and the interfaces. |
The short version
Airtable's ceiling is real but it is higher than most teams think, and the ceiling you hit is usually one table, one query shape, or one concurrency hazard — not the platform. Diagnose the specific symptom, apply the cheap fixes, and if you still need to move, move the system of record and keep the interface people already know.
BaseBrainers does this triage as a fixed-scope engagement: we audit the base, tell you honestly whether you need to migrate, and if you do, we build the sync layer and the Postgres model. Start with data migration or enterprise-level Airtable solutions, or just describe the problem and we will tell you which of the three shapes fits.