Load Airtable data to Google Cloud Storage

Build a Airtable to Google Cloud Storage pipeline with your coding agent. One prompt scaffolds it with the dltHub AI harness, plus the Airtable API base URL, auth, endpoints, and incremental loading.

Source
Airtable
Destination
Google Cloud Storage
Write data from any source to Google Cloud Storage buckets as Parquet, JSONL or CSV files with the dlt filesystem destination.

Airtable is a collaborative database service with REST endpoints for reading and managing records, bases, tables, and related metadata. Everything needed to build a working Airtable → Google Cloud Storage pipeline is on this page: the API's base URL, authentication, endpoints, pagination and incremental field — plus a prompt that hands the whole job to your coding agent.


Build your Airtable to Google Cloud Storage pipeline

Paste this prompt into Claude, Codex, or Cursor. The agent does the rest.

Prompt
Run uvx dlthub-init@latest to build a pipeline from Airtable to Google Cloud Storage and run it on dltHub

That scaffolds a dltHub workspace and installs the dltHub AI harness — the project rules, the secrets-management skill, and the dlt MCP server your agent needs to work safely. From there it reads the Airtable API, proposes the endpoints to load, then writes, runs and validates the pipeline while you review rather than type. Credentials are inspected through MCP tools, so your agent never reads secrets.toml itself. How the LLM-native workflow works →

Prefer to write it yourself? Every fact the agent uses is below.


Airtable API at a glance

Base URLhttps://api.airtable.com/v0
Example endpointGET {baseId}/{tableIdOrName}
Records found atrecords
Authenticationall requests require a Bearer personal access token — sent in the Authorization header, prefixed Bearer
PaginationCursor-based via offset, next cursor at offset, page size via pageSize (default 100, max 100). Airtable's List records endpoint returns one page at a time. The response includes an offset token when more records remain; send that exact value as the offset query parameter on the next request. Stop when offset is absent. pageSize controls records per request and defaults to 100; maxRecords is an optional total-record cap, not a page-size limit. Bearer authentication does not change pagination. Filtering or sorting by createdTime is separate from pagination and does not replace the offset cursor.
Incremental fieldcreatedTime
Record idid
API referencehttps://airtable.com/developers/web/api/authentication

These values come from the Airtable API reference — the authoritative source if anything here looks out of date.


How do I authenticate with the Airtable API?

Send the personal access token on every HTTPS request in the HTTP header Authorization: Bearer YOUR_TOKEN. Airtable does not support passing personal access tokens in the legacy api_key URL parameter; record-list requests require the data.records

scope and access to the target base.

1. Get your credentials

  1. Sign in to Airtable and open the Developer Hub at https://airtable.com/create/tokens (or open Developer Hub and choose Personal access tokens).
  2. Click Create token / Create new token and give it a unique name.
  3. Click Add a scope and grant at least data.records
    for reading records.
  4. Click Add a base, select the base(s) the pipeline must read, or grant the appropriate workspace/resource access. The token can only access resources selected here and resources the creating user is permitted to access.
  5. Create the token and immediately copy the complete token value. Airtable displays the secret only once; if it is lost, generate a replacement token. Use the entire PAT value, not merely the visible token ID.
  6. Send it on every HTTPS request as Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN. Legacy API-key URL authentication is not supported for personal access tokens.

2. Add them to .dlt/secrets.toml

[sources.airtable_source] api_key = "patXXXXXXXXXXXXXX.xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

dlt reads this file automatically at runtime. With the harness, the setup-secrets skill prompts you for the values and never handles the raw credential in chat. For production, see setting up credentials with dlt.


What Airtable data can I load into Google Cloud Storage?

These are the Airtable endpoints dlt can load into Google Cloud Storage:

ResourceEndpointMethodData selectorDescription
list_records{baseId}/{tableIdOrName}GETrecordsList table records; pageSize max 100, continuation uses response offset. Supports filterByFormula, sorting, field selection, and views.
get_record{baseId}/{tableIdOrName}/{recordId}GETRetrieve one record.
list_basesmeta/basesGETbasesList accessible bases, up to 1,000 per page; continuation uses response offset.
get_base_schemameta/bases/{baseId}/tablesGETtablesRetrieve the table/field schema for a base.
get_base_collaboratorsmeta/bases/{baseId}GETRetrieve base information; optional include can add collaborators and related objects.
list_comments{baseId}/{tableIdOrName}/{recordId}/commentsGETcommentsList record comments, newest first; pageSize max 100 and continuation uses offset.
create_records{baseId}/{tableIdOrName}POSTrecordsCreate one or multiple records; write scope required.
update_record{baseId}/{tableIdOrName}/{recordId}PATCH or PUTPATCH updates supplied fields; PUT clears unspecified fields.
create_basemeta/basesPOSTtablesCreate a base and return its schema.
create_fieldmeta/bases/{baseId}/tables/{tableId}/fieldsPOSTCreate a field and return its schema.

How do I load only new Airtable records?

Airtable exposes createdTime on {baseId}/{tableIdOrName}, so dlt can request only the records that changed since the last run. Set it as the cursor_path and dlt tracks the high-water mark for you between runs.

{"name": "records", "endpoint": { "path": "{baseId}/{tableIdOrName}", "data_selector": "records", "incremental": {"cursor_path": "createdTime", "initial_value": "2024-01-01T00:00:00Z"}, }}

On the first run dlt loads everything from initial_value; on every run after that it requests only what changed and appends with write_disposition="merge" if you set a primary key. See incremental loading.


What does the generated Airtable pipeline look like?

A standard dlt REST API pipeline — the same code you would write by hand, loading GET /v0/{baseId}/{tableIdOrName} (list records) and GET /v0/meta/bases (list bases / metadata discovery) from the Airtable API into Google Cloud Storage:

import dlt from dlt.sources.rest_api import RESTAPIConfig, rest_api_resources @dlt.source def airtable_source(api_token=dlt.secrets.value): config: RESTAPIConfig = { "client": { "base_url": "https://api.airtable.com/v0", "auth": {"type": "bearer", "token": api_token}, }, "resources": [ {"name": "records", "endpoint": {"path": "{baseId}/{tableIdOrName}", "data_selector": "records"}}, {"name": "bases", "endpoint": {"path": "meta/bases", "data_selector": "bases"}} ], } yield from rest_api_resources(config) def load_airtable_to_google_cloud_storage_filesystem() -> None: pipeline = dlt.pipeline( pipeline_name="airtable_pipeline", destination="filesystem", dataset_name="airtable_data", ) load_info = pipeline.run(airtable_source()) print(load_info) if __name__ == "__main__": load_airtable_to_google_cloud_storage_filesystem()

Run it with uv run python airtable_pipeline.py. The agent iterates on this until it loads cleanly — you review and approve, rather than write it from scratch.


How do I configure Google Cloud Storage as the destination?

dlt writes to Google Cloud Storage through its filesystem destination; the gs:// scheme in bucket_url selects it. Install the extra with uv add "dlt[gs]", then add to .dlt/config.toml and .dlt/secrets.toml:

# .dlt/config.toml [destination.filesystem] bucket_url = "gs://<bucket>/<path>" # .dlt/secrets.toml [destination.filesystem.credentials] project_id = "<project id>" private_key = "<private key>" client_email = "<service account email>"

dlt writes JSONL by default; pass loader_file_format="parquet" to pipeline.run() for Parquet. Delta and Iceberg table formats are supported too. See the dlt filesystem destination docs.

Changing bucket_url is all it takes to write the same data to Amazon S3, Azure Blob Storage or local files instead; see dlt's filesystem destination for all four.


How do I query Airtable data in Google Cloud Storage?

After a run, pipeline.dataset() holds the loaded tables, one per resource. A Relation is a query on that dataset, either a whole table or a SQL string, and reading it gives you the data as a Pandas DataFrame, a PyArrow table or Python tuples. Nothing is read until you ask for it. A filesystem destination holds files rather than tables, so dlt reads them through DuckDB views and the interface is the same as for a SQL destination; for frequent reads load Delta or Iceberg tables, which DuckDB reads only as far as the query needs (see reading data from filesystem).

import dlt pipeline = dlt.pipeline("airtable_pipeline") # Step 1: Get the dataset from the pipeline dataset = pipeline.dataset() # Step 2: Get a Relation, either a whole table... records = dataset.table("records") # ...or any SQL query against Google Cloud Storage sample = dataset("SELECT * FROM records LIMIT 100") # Step 3: Read the data df = records.df() # or .df(chunk_size=50) for a large table arrow_table = sample.arrow() # a PyArrow Table rows = sample.fetchall() # a list of Python tuples # Which tables were loaded, and how big are they? print(dataset.row_counts().df()) """ table_name row_count 0 records 13 1 bases 3 """

The columns are the fields the Airtable API returns. Your agent can run the same queries through the MCP server's execute_sql_query tool, and uv run dlthub show opens the Pipeline Dashboard with the schema, load metrics and a query box. See access loaded data in Python and exploring it in marimo notebooks.


How do I deploy the Airtable to Google Cloud Storage pipeline in production?

The pipeline runs locally, which is ideal for prototyping and one-off analysis. When you need it on a schedule, monitored on every load, and shared with your team, deploy the same dlt code on the dltHub platform — no infrastructure to maintain. The prompt above already ends with "run it on dltHub", so your agent can take it there directly.

  • Deploy & schedule — run the pipeline as a managed job with automatic retries.
  • Monitor — observable job queues, alerting, and load metrics for every run.
  • Transform — promote raw Airtable loads into governed, documented models.
  • Visualize & share — explore data in notebooks and publish live dashboards instead of static screenshots.

Book a demo →


What other destinations can I load Airtable data to?

dlt loads into any of these — only the destination argument changes:

DestinationExample value
PostgreSQL"postgres"
BigQuery"bigquery"
Snowflake"snowflake"
Redshift"redshift"
Databricks"databricks"
Filesystem (S3, GCS, Azure)"filesystem"

Set dlt.pipeline(destination="snowflake") and add credentials in .dlt/secrets.toml. On the dltHub platform the same pipeline runs against a managed Iceberg lakehouse. See the full destinations list.


Next steps

Was this page helpful?

Community Hub

Need more dlt context for Airtable to Google Cloud Storage?

Request dlt skills, commands, AGENT.md files, and AI-native context.