Airtable has no "export base" button. Downloads work one grid view at a time, as CSV, and include only what that view shows. A complete export of a base has four parts: every table's records, the links between them, the field setup, and the attachment files.
What a complete export needs
| Part | Why it matters | CSV download | API |
|---|---|---|---|
| Every record in every table | The data itself | One view per download | Yes |
| Record IDs | Rebuilding links and matching files to records | No | Yes |
| Linked records | Relationships between tables | As text of the linked record's primary field | As record IDs |
| Field names and types | Rebuilding the base | No | Yes, with the schema scope |
| Attachment files | Your documents and images | Links that expire after a few hours | Links that expire after a few hours |
The CSV route gets you readable tables. The API route gets you everything needed to rebuild the base accurately.
By hand: CSV downloads
For each table:
- Create a new grid view, or pick one with no filters and no hidden fields. Hidden fields are left out of the download and filters remove records.
- Open the view's menu (the arrow next to its name) and choose Download CSV.
- Rename the file after its table; Airtable names it after the view.
Then download the attachments separately, straight away, because the links in the CSVs stop working after a few hours. See how to download all attachments.
Finally, write down each field's type and options (single select choices, formulas, lookups, rollups). CSV files keep values, not field settings, and you'll need them to rebuild the base.
CSV download is available in the web and desktop apps, not on mobile. A base owner can block downloads from shared views.
With a script: JSON with record IDs
The Airtable Web API returns each table's field definitions and every record with its ID, with links between records as record IDs. This script saves schema.json and one JSON file per table.
- Create a personal access token with the
data.records:readandschema.bases:readscopes and access to the base. - Run it with Node.js 20 or later:
AIRTABLE_TOKEN=pat... node export-base.mjs appXXXXXXXXXXXXXX
// Saves the base's schema and every table's records as JSON in export-<base ID>/.
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
const [baseId] = process.argv.slice(2);
const headers = { Authorization: `Bearer ${process.env.AIRTABLE_TOKEN}` };
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function get(url) {
while (true) {
const response = await fetch(url, { headers });
if (response.status === 429) {
await sleep(30_000); // Airtable's rate limit asks for a 30-second pause.
continue;
}
if (!response.ok) throw new Error(`Airtable answered ${response.status}`);
await sleep(250); // Stay under 5 requests per second.
return response.json();
}
}
const folder = `export-${baseId}`;
await mkdir(folder, { recursive: true });
const { tables } = await get(`https://api.airtable.com/v0/meta/bases/${baseId}/tables`);
await writeFile(join(folder, "schema.json"), JSON.stringify(tables, null, 2));
for (const table of tables) {
const records = [];
let offset;
do {
const url = new URL(`https://api.airtable.com/v0/${baseId}/${table.id}`);
url.searchParams.set("returnFieldsByFieldId", "true");
if (offset) url.searchParams.set("offset", offset);
const page = await get(url);
records.push(...page.records);
offset = page.offset;
} while (offset);
await writeFile(join(folder, `${table.id}.json`), JSON.stringify(records, null, 2));
console.log(`${table.name}: ${records.length} records`);
}
Records are saved with field IDs rather than names, so renaming a field later doesn't break the export; schema.json maps each ID to its name and type. Attachment fields contain links that expire, so run the attachment script right afterwards if you need the files.
Each table takes one request per 100 records. Check your plan's monthly API allowance before exporting large bases on a Free workspace.
What no export includes
Interfaces, automations, extension settings, exact view configuration (filters, sorts, hidden fields, colors), permissions and record revision history stay in Airtable. Record comments are available through a separate API endpoint, one request per record. Write down your automations and take screenshots of important interfaces if you might need to rebuild them.
Keeping exports current
An export is a copy of one moment. If the base keeps changing, you'll need to repeat the export, keep older ones, and notice when one fails. That's the job a scheduled backup does; see how to back up Airtable for the options, and how to restore a base from a backup for getting an export back into Airtable.
Sources: Airtable's support article on views and CSV export, the Web API reference and rate limits, checked October 17, 2026.