Airtable keeps your data safe on its side, but that is not the same as having your own copy. A deleted table, a bad bulk edit or a lost workspace login can still ruin your week. Snapshots and the trash help for a limited time. A copy you hold yourself does not expire.

A complete backup of a base has three parts, and most people only save the first:

  1. Records: the data in every table, not just one view.
  2. Schema: the table structure, field types, select options, formulas and linked tables. Without it, a pile of CSVs is hard to rebuild.
  3. Attachments: the actual files. A CSV only contains links to them.

Here are four ways to do this for free, from quick to automated.

1. The manual way: download CSV per view

In Airtable, open a view, click the view name, then Download CSV. It works, but has limits:

  • It exports one view at a time. If the view has filters or hidden fields, the CSV has them too, so you can silently miss records or columns.
  • You have to repeat it for every table and every time you want a fresh copy.
  • Attachments come out as URLs, not files.
  • Nothing is saved about the structure: no field types, no formulas, no select options.

For a one-table base you check once a month, this is fine. For anything bigger, use one of the next options.

2. Free browser tools that run client-side

If you don't want to write code, these tools run entirely in your browser. You paste an Airtable personal access token, and the requests go from your browser straight to api.airtable.com. Nothing goes through a server and nothing is stored.

First, create a read-only personal access token at airtable.com/create/tokens. Give it the scopes data.records:read and schema.bases:read, and add only the base you want to back up. Delete the token when you are done.

Then:

  • Base to CSV downloads every table as its own CSV, all records and all fields, bundled in one ZIP.
  • Schema export gives you a data dictionary as CSV, Markdown or raw JSON. It only needs schema.bases:read, so the token cannot read your records.
  • Attachment downloader downloads every file in a table or view as a ZIP, one folder per record, plus a manifest CSV.
  • Record counter shows how many records each table has and how close you are to your plan's limit. It also lists which fields are never filled in. Handy before you decide what is worth backing up.

Run them in that order: schema, CSVs, attachments. On a base with a few thousand records the whole thing takes a few minutes.

3. A script you control

If you prefer to own the whole process, the Airtable REST API is simple. Three facts matter:

  • A list request returns at most 100 records per page. If the response contains an offset, send it back to get the next page.
  • Airtable allows about 5 requests per second per base, so pause between pages.
  • Attachment URLs expire after about two hours. Download the files in the same run that fetched the records. A URL saved in last month's CSV will not work anymore (more on that in this guide on expired attachment links).

This Node.js script (version 18 or newer, no dependencies) saves the schema, every table as JSON, and every attachment:

// backup.mjs: AIRTABLE_TOKEN=pat... BASE_ID=app... node backup.mjs import { mkdir, writeFile } from "node:fs/promises"; const { AIRTABLE_TOKEN: token, BASE_ID: base } = process.env; const api = "https://api.airtable.com/v0"; const headers = { Authorization: `Bearer ${token}` }; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); async function get(url) { const res = await fetch(url, { headers }); if (res.status === 429) { await sleep(30000); return get(url); } if (!res.ok) throw new Error(`${res.status} ${url}`); return res.json(); } const stamp = new Date().toISOString().slice(0, 10); const dir = `backup-${stamp}`; await mkdir(`${dir}/files`, { recursive: true }); // 1. Schema const schema = await get(`${api}/meta/bases/${base}/tables`); await writeFile(`${dir}/schema.json`, JSON.stringify(schema, null, 2)); // 2. Records, page by page for (const table of schema.tables) { const records = []; let offset; do { const qs = new URLSearchParams({ pageSize: "100" }); if (offset) qs.set("offset", offset); const page = await get(`${api}/${base}/${table.id}?${qs}`); records.push(...page.records); offset = page.offset; await sleep(250); } while (offset); await writeFile(`${dir}/${table.name}.json`, JSON.stringify(records, null, 2)); // 3. Attachments, right away while the URLs are valid for (const rec of records) { for (const value of Object.values(rec.fields)) { if (!Array.isArray(value)) continue; for (const f of value) { if (!f?.url || !f?.filename) continue; const file = await fetch(f.url); if (!file.ok) { console.warn("skipped", f.filename); continue; } await writeFile(`${dir}/files/${rec.id}-${f.id}-${f.filename}`, Buffer.from(await file.arrayBuffer())); } } } console.log(`${table.name}: ${records.length} records`); } 

Two notes. The JSON keeps linked records, lookups and multi-selects exactly as Airtable returns them, which is more faithful than CSV. If you want CSV for spreadsheets, convert the JSON afterwards or use the browser tool from section 2. And the script lives on your machine, so the token never leaves it. Keep the token in an environment variable, not in the file.

4. Make it happen on a schedule

A backup you have to remember is a backup that stops. Some options for automating it:

  • Cron or a scheduled GitHub Action running the script above, committing or uploading the output to storage you control. The most flexible option, and you maintain it.
  • An Airtable automation with a scheduled trigger that runs a script or sends a webhook. It works inside Airtable's own limits, and the free plan has few automation runs.
  • Make or Zapier with a schedule trigger that lists records and writes them to Drive or Dropbox. Fine for small bases, but watch the operation counts.
  • Emailing a view as CSV: if what you need is a regular CSV of one view in your inbox, ViewCourier does this on a daily, weekly or monthly schedule, with a free plan. It exports views, so it is a good fit for key tables rather than a full base dump with attachments.

There is a step-by-step version of the CSV route in this guide to automatic Airtable CSV backups. I also compared three ways of scheduling CSV emails in this write-up.

A sensible routine

  • Once now: run the schema export and the full-base CSV export, store the ZIPs somewhere that is not Airtable.
  • Weekly or monthly: a scheduled script or emailed view CSVs for the tables that change.
  • Before big changes: run the tools again. A fresh copy takes minutes.
  • Test a restore once. Open a CSV, check that linked records and dates look right, and check that the schema file tells you what each field was.

The one habit that matters is keeping the copy outside the system it is backing up.

Disclosure: written by the team behind ViewCourier.