# Airtable

Create, update, upsert, find and delete records in Airtable, upload files and comment on records, and read or change bases, tables and fields.

## Connect Airtable

1. In the sidebar, open **Connections** and press **Add connection**.
2. Type `airtable` and choose **Airtable**.
3. Choose **Sign in with Airtable**.
4. Press **Sign in with Airtable** at the bottom of the sheet, then choose your account in Airtable’s window and allow access.

Or choose **Paste your personal access token**, paste it, and press **Test and save**. It stays until someone deletes it.

Sign in with Airtable and pick the bases the connection may use, or paste a personal access token (airtable.com/create/tokens: add the scopes data.records:read/write, data.recordComments:read/write, schema.bases:read/write and user.email:read, and the bases it may reach).

**What if it says “Sign-in isn’t set up here yet”?**

Signing in with Airtable needs a Airtable app on this installation, and it has none yet. Until it is set up, **Paste your personal access token** works without it.

**On Cloud:** The sheet says “It’s set up once for everyone who uses this service, not by an organization.”

**Self-hosted:** An admin of the installation sees **Set up Airtable sign-in** instead, and sets it up once for everyone. Everyone else sees who to ask.

1. Create an app in Airtable’s developer settings ([Airtable’s guide](https://airtable.com/create/tokens)).
2. In GoRunner, copy the **Redirect address to add in Airtable’s developer settings**, and add it to the app.
3. Paste the **Client ID** and **Client secret**, then press **Save and sign in**.

[Set up a sign-in app](https://docs.gorunner.io/self-host/oauth-apps#other-providers)

**Can I use my own Airtable app?**

Yes. In the sheet, open **Use your own Airtable app** and paste its **Client ID** and **Client secret**. Add the redirect address it shows to your app first. The connection then signs in through your app instead of the installation’s.

[Connections](https://docs.gorunner.io/build/connections) says how to sign in again, rename or delete it. In a product that embeds GoRunner, **Add connection** can be missing: then [your provider makes connections](https://docs.gorunner.io/embed/customer-connections) for you.

## Start a workflow

Add a trigger and choose **Airtable**. The trigger uses the same connection as the steps.

### On Record Created or Updated

Checks an Airtable table about once a minute and starts a run for each record created, or created or changed, since the check before, oldest first. The first check after publishing only takes note of where the table is (it starts nothing); changing the trigger starts over the same way. It asks Airtable only for records newer than the last check, at most 100 a check (the rest follow a minute later). For changes, the table needs a Last modified time field, picked as the Trigger Field.

- **Base · Required**: The base.
- **Table · Required**: The table to watch.
- **Trigger on · Required**: Which records start a run. Options: Record created, Record created or updated. Default: Record created.
- **Trigger Field · Optional**: A Created time or Last modified time field. Required for "created or updated" (a Last modified time field); for "created", leave it empty to use the time Airtable records for each record.
- **View · Optional**: Only records in this view.
- **Only Records Matching · Optional**: An Airtable formula a record must make true, such as {Status} = "Ready". Empty watches every record.

A later step can use its data, such as `{{trigger.change_type}}`, `{{trigger.createdTime}}`, `{{trigger.fields}}` and 1 more. See [Use data from earlier steps](https://docs.gorunner.io/build/use-data-from-earlier-steps).

## Do things in Airtable

Add an **Airtable** step, choose a **Resource**, then an **Operation**. Choose a row to see its fields.

- [Record](https://docs.gorunner.io/apps/airtable#fields-f-record): Create · Create or Update · Update · Get · Search · Delete · Upload File
- [Record Comment](https://docs.gorunner.io/apps/airtable#fields-f-comment): Create · Get Many · Update · Delete
- [Base](https://docs.gorunner.io/apps/airtable#fields-f-base): Get Many · Get Schema · Create
- [Table](https://docs.gorunner.io/apps/airtable#fields-f-table): Create · Update
- [Field](https://docs.gorunner.io/apps/airtable#fields-f-field): Create · Update
- [User](https://docs.gorunner.io/apps/airtable#fields-f-user): Get Current User

Later steps read a step’s output by its name: see [Use data from earlier steps](https://docs.gorunner.io/build/use-data-from-earlier-steps).

## Limits

- A reply from Airtable can be up to 16 MB (a file download can have its own limit). A larger one fails the step; it is never cut short.
- When Airtable says to slow down (429), the step waits as long as it asks, if the step’s time allows. Otherwise it fails and says when to try again.

Not in your list? See [When an app isn’t here](https://docs.gorunner.io/apps/when-an-app-isnt-here#q-not-in-list).

## For developers

In the API, which calls apps pieces, Airtable is `pieceId: "airtable"` with `actionId: "airtable"`, set by `resource` and an `operation_…` field, such as `operation_base`. Its trigger is `airtabletrigger` / `airtable_poll`. [Get an app](https://docs.gorunner.io/api/apps/get-app) returns every field.

It can change something outside the run (`writes_external`). See [How versions and side effects work](https://docs.gorunner.io/apps#q-versions).

### Airtable › Record

### Create

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Fields · Optional**: Cell values by field name, such as {"Name": "Ada", "Status": "Open", "Tags": ["Launch"], "Due": "2026-11-07"}. For several records, a list: [{"Name": "Ada"}, {"Name": "Grace"}] (for Update, each with its "id").
- **Typecast · Optional**: Let Airtable convert text into the field's type: dates, numbers, select options (created when missing), linked records by name. Off by default.

### Create or Update

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Fields · Optional**: Cell values by field name, such as {"Name": "Ada", "Status": "Open", "Tags": ["Launch"], "Due": "2026-11-07"}. For several records, a list: [{"Name": "Ada"}, {"Name": "Grace"}] (for Update, each with its "id").
- **Fields to Match On · Required**: One to three field names, separated by commas, that identify a record (an email, an order number). A record with the same values is updated; none is created; more than one fails the step.
- **Typecast · Optional**: Let Airtable convert text into the field's type: dates, numbers, select options (created when missing), linked records by name. Off by default.

### Update

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Optional**: The record's id (rec…) or link. For Delete, several ids separated by commas, or a list. For Update of several records, leave it empty and give each record's id in Fields.
- **Fields · Optional**: Cell values by field name, such as {"Name": "Ada", "Status": "Open", "Tags": ["Launch"], "Due": "2026-11-07"}. For several records, a list: [{"Name": "Ada"}, {"Name": "Grace"}] (for Update, each with its "id").
- **Typecast · Optional**: Let Airtable convert text into the field's type: dates, numbers, select options (created when missing), linked records by name. Off by default.

### Get

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Optional**: The record's id (rec…) or link. For Delete, several ids separated by commas, or a list. For Update of several records, leave it empty and give each record's id in Fields.
- **Return Fields · Optional**: Only these fields (names separated by commas). Empty returns every field.

### Search

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Match Fields · Optional**: Find records whose fields equal these values, such as {"Email": "{{trigger.email}}", "Status": "Open"}. Values from earlier steps are matched as values, never read as formula.
- **Filter by Formula · Optional**: An Airtable formula a record must make true, such as AND({Status} = "Open", IS_AFTER({Due}, TODAY())). It is sent as written; to match a value from an earlier step, use Match Fields.
- **View · Optional**: Only records in this view, in its order unless Sort is set.
- **Sort · Optional**: Sort rules, such as [{"field": "Due", "direction": "asc"}, {"field": "Name", "direction": "desc"}].
- **Return Fields · Optional**: Only these fields (names separated by commas). Empty returns every field.
- **Return All · Optional**: Read every record, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many records to return (1–2000). Default: 50. Shows when **Return All** is off.

### Delete

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Optional**: The record's id (rec…) or link. For Delete, several ids separated by commas, or a list. For Update of several records, leave it empty and give each record's id in Fields.

### Upload File

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Optional**: The record's id (rec…) or link. For Delete, several ids separated by commas, or a list. For Update of several records, leave it empty and give each record's id in Fields.
- **Attachment Field · Required**: The attachment field to add the file to.
- **File · Required**: Upload a file, or switch to an expression to use one from an earlier step (such as {{steps.download.result}}). At most 5 MB; for a bigger file, set the attachment field to [{"url": "https://…"}] with Update.

### Airtable › Record Comment

### Create

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Required**: The record's id (rec…) or link.
- **Text · Required**: The comment. Mention someone with @[usr…] (their user id).
- **Reply To · Optional**: A comment id (com…) to reply to in its thread.

### Get Many

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Required**: The record's id (rec…) or link.
- **Return All · Optional**: Read every comment, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many comments to return (1–2000). Default: 50. Shows when **Return All** is off.

### Update

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Required**: The record's id (rec…) or link.
- **Comment ID · Required**: The comment's id (com…). Only comments the connection's user wrote can be changed.
- **Text · Required**: The comment. Mention someone with @[usr…] (their user id).

### Delete

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Record ID · Required**: The record's id (rec…) or link.
- **Comment ID · Required**: The comment's id (com…). Only comments the connection's user wrote can be changed.

### Airtable › Base

### Get Many

- **Permission Level · Optional**: Only bases where the connection's user has one of these levels. Empty lists every base. Options: None, Read, Comment, Edit, Create (owner or creator).
- **Return All · Optional**: Read every base, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many bases to return (1–2000). Default: 50. Shows when **Return All** is off.

### Get Schema

- **Base · Required**: The base.

### Create

- **Name · Required**: The new base's name.
- **Workspace ID · Required**: The workspace to create it in (wsp…): open the workspace in Airtable and copy the id from its address.
- **Tables · Required**: At least one table with at least one field; each table's first field is its primary field, such as [{"name": "Tasks", "fields": [{"name": "Name", "type": "singleLineText"}, {"name": "Done", "type": "checkbox", "options": {"color": "greenBright", "icon": "check"}}]}].

### Airtable › Table

### Create

- **Base · Required**: The base.
- **Name · Optional**: The table's name (required to create; for Update, a new name or empty to keep it).
- **Description · Optional**: What the table holds (at most 20,000 characters).
- **Fields · Required**: At least one field; the first is the primary field, such as [{"name": "Name", "type": "singleLineText"}, {"name": "Due", "type": "date", "options": {"dateFormat": {"name": "iso"}}}].

### Update

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Name · Optional**: The table's name (required to create; for Update, a new name or empty to keep it).
- **Description · Optional**: What the table holds (at most 20,000 characters).

### Airtable › Field

### Create

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Name · Optional**: The field's name (required to create; for Update, a new name or empty to keep it).
- **Type · Required**: The field's type. Some types need Options. Options: Single line text to Barcode (21 options). Default: Single line text.
- **Description · Optional**: What the field holds (at most 20,000 characters).
- **Options · Optional**: The type's options, such as {"precision": 2} for Number, {"choices": [{"name": "Open"}, {"name": "Done"}]} for a select, {"color": "greenBright", "icon": "check"} for Checkbox. For Update, only a formula field's {"formula": "…"} can change.

### Update

- **Base · Required**: The base.
- **Table · Required**: The table.
- **Field · Required**: The field to change.
- **Name · Optional**: The field's name (required to create; for Update, a new name or empty to keep it).
- **Description · Optional**: What the field holds (at most 20,000 characters).
- **Options · Optional**: The type's options, such as {"precision": 2} for Number, {"choices": [{"name": "Open"}, {"name": "Done"}]} for a select, {"color": "greenBright", "icon": "check"} for Checkbox. For Update, only a formula field's {"formula": "…"} can change.

### Airtable › User

### Get Current User

Nothing to fill in.

Source: https://docs.gorunner.io/apps/airtable
