npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dc-airtable-cli

v1.0.0

Published

Script-friendly CLI for Airtable record CRUD operations

Readme

Airtable CLI

A script-friendly, production-ready command-line interface for Airtable record CRUD operations, schema inspection, and data management.

Overview

airtable-cli is a TypeScript-based CLI tool that provides safe, efficient access to Airtable's REST API. It's designed for:

  • Automation: Build scripts and workflows around Airtable data
  • DevOps: Manage data pipelines and integrations
  • Testing: Query and manipulate test data
  • Batch operations: Create, update, or upsert records at scale
  • Schema inspection: Discover table structures and field types

Features

  • CRUD Operations: Create, read, update, delete, and upsert records
  • Flexible Filtering: Use Airtable's powerful filterByFormula syntax
  • Batch Processing: Handle up to 10 records per request with automatic batching
  • Multiple Output Formats: JSON, tab-separated plain text, or quiet mode
  • Schema Inspection: List tables and fields with type information
  • Configuration Management: Store tokens and base aliases securely
  • Dry-run Mode: Preview changes before executing mutations
  • Type Safety: Written in TypeScript with full type checking

Installation

From NPM

npm install -g airtable-cli

From Source

git clone <repo>
cd airtable-cli
npm install
npm run build
npm install -g .

Quick Start

1. Set Your API Token

Get a Personal Access Token from airtable.com/create/tokens.

# Option 1: Environment variable (recommended)
export AIRTABLE_TOKEN="pat_xxxxx"

# Option 2: Config file
airtable config set token "pat_xxxxx"

2. List Records

airtable list <base-id> <table-name>

Example:

airtable list appXxxx Contacts

3. Create a Record

airtable create <base-id> <table-name> --data '{"Name":"John","Email":"[email protected]"}'

4. Query with Filters

airtable list appXxxx Contacts --filter "AND({Status}='Active',{Priority}>5)" --sort Priority --desc

See QUICKSTART.md for more examples.

Command Reference

Record Operations

list

List records from a table with filtering and sorting.

airtable list <base> <table> [options]

Options:
  -f, --filter <formula>    Airtable filterByFormula expression
  --fields <fields>         Comma-separated field names to return
  --sort <field>            Field to sort by
  --desc                    Sort descending (default: ascending)
  --max <n>                 Max records to return (default: 100)
  --offset <cursor>         Pagination cursor for next page
  --all                     Fetch all records automatically (paginate)
  --view <name>             View name or ID to query

Examples:

# List all contacts
airtable list myBase Contacts

# List active contacts, 50 per page
airtable list myBase Contacts --filter "{Status}='Active'" --max 50

# List and sort by priority
airtable list myBase Contacts --sort Priority --desc

# Fetch everything with automatic pagination
airtable list myBase Contacts --all

# Output as JSON
airtable list myBase Contacts --json

get

Get a single record by ID.

airtable get <base> <table> <recordId> [options]

Options:
  --fields <fields>         Comma-separated field names to return

Examples:

# Get record recXxxx
airtable get myBase Contacts recXxxx

# Get specific fields only
airtable get myBase Contacts recXxxx --fields "Name,Email"

create

Create one or more records.

airtable create <base> <table> [options]

Options:
  -d, --data <json>         JSON object or array of records
  -f, --file <path>         Read JSON from file (use - for stdin)
  --typecast                Auto-convert field types
  --dry-run                 Preview without creating

Examples:

# Create single record
airtable create myBase Contacts --data '{"Name":"Jane","Email":"[email protected]"}'

# Create multiple records
airtable create myBase Contacts --data '[
  {"Name":"Jane","Email":"[email protected]"},
  {"Name":"Bob","Email":"[email protected]"}
]'

# Create from file
airtable create myBase Contacts --file records.json

# Create from stdin
cat records.json | airtable create myBase Contacts --file -

# Preview what would be created
airtable create myBase Contacts --file records.json --dry-run

# Auto-convert types (e.g., "99.99" → 99.99)
airtable create myBase Contacts --file records.json --typecast

update

Update a single record.

airtable update <base> <table> <recordId> [options]

Options:
  -d, --data <json>         JSON object of fields to update
  -f, --file <path>         Read JSON from file (use - for stdin)
  --typecast                Auto-convert field types
  --dry-run                 Preview changes without updating

Examples:

# Update one field
airtable update myBase Contacts recXxxx --data '{"Status":"Active"}'

# Update multiple fields
airtable update myBase Contacts recXxxx --data '{"Status":"Active","Priority":8}'

# Update from file
airtable update myBase Contacts recXxxx --file updates.json

# Preview changes
airtable update myBase Contacts recXxxx --file updates.json --dry-run

upsert

Create or update records (merge on specified fields).

airtable upsert <base> <table> --merge-on <fields> [options]

Options:
  --merge-on <fields>       Comma-separated fields to match on (required)
  -d, --data <json>         JSON array of records
  -f, --file <path>         Read JSON from file (use - for stdin)
  --typecast                Auto-convert field types
  --dry-run                 Preview without upserting

Examples:

# Upsert on Email field
airtable upsert myBase Contacts --merge-on Email --data '[
  {"Email":"[email protected]","Name":"John Doe","Status":"Active"},
  {"Email":"[email protected]","Name":"Jane Smith","Status":"Pending"}
]'

# Upsert on multiple fields
airtable upsert myBase Contacts --merge-on "Email,Name" --file records.json

# Preview without executing
airtable upsert myBase Contacts --merge-on Email --file records.json --dry-run

delete

Delete one or more records.

airtable delete <base> <table> [recordIds...] [options]

Options:
  -f, --file <path>         Read record IDs from file (use - for stdin)
  --force                   Skip confirmation (required for non-interactive)
  --dry-run                 Preview without deleting

Examples:

# Delete single record
airtable delete myBase Contacts recXxxx --force

# Delete multiple records
airtable delete myBase Contacts recXxxx recYyy recZzz --force

# Delete from file
airtable delete myBase Contacts --file ids.txt --force

# Preview deletions
airtable delete myBase Contacts recXxxx --dry-run

Schema Commands

fields

List field names, IDs, and types for a table.

airtable fields <base> <table>

Examples:

# List all fields
airtable fields myBase Contacts

# Output as JSON
airtable fields myBase Contacts --json

# Output as plain text
airtable fields myBase Contacts --plain

tables

List all tables in a base.

airtable tables <base>

Examples:

# List tables
airtable tables myBase

# Output as JSON
airtable tables myBase --json

Configuration Commands

config set

Store configuration values.

airtable config set <key> <value>

Examples:

# Store API token
airtable config set token "pat_xxxxx"

# Store default base ID
airtable config set defaultBase "appXxxx"

config get

Retrieve configuration values.

airtable config get <key>

Examples:

airtable config get token
airtable config get defaultBase

config list

Show all stored configuration (with token masked for security).

airtable config list

alias

Create shortcuts for base IDs.

airtable alias <name> <baseId>

Examples:

# Create alias
airtable alias myBase "appXxxx"

# Use alias in commands
airtable list myBase Contacts

Global Options

These options work with all commands:

--json              Output as JSON (default for non-TTY)
--plain             Output as tab-separated values
-q, --quiet         Suppress non-essential output
--no-color          Disable colored output
--token <token>     Override AIRTABLE_TOKEN env var
--config <path>     Override config file location
--dry-run           Preview mutations without executing

Output Formats

JSON Output

airtable list myBase Contacts --json

Returns structured data:

{
  "records": [
    {
      "id": "recXxxx",
      "fields": {
        "Name": "John Doe",
        "Email": "[email protected]"
      }
    }
  ],
  "count": 1
}

Plain Text Output

airtable list myBase Contacts --plain

Returns tab-separated values:

recXxxx  John Doe  [email protected]
recYyy   Jane Smith [email protected]

Advanced Usage

Filtering with Formulas

Use Airtable's formula syntax for complex queries:

# Active records with high priority
airtable list myBase Contacts \
  --filter "AND({Status}='Active',{Priority}>7)" \
  --sort Priority --desc

# Records from the last 30 days
airtable list myBase Contacts \
  --filter "IS_AFTER({Created},DATEADD(TODAY(),-30,'days'))"

# Search by text
airtable list myBase Contacts \
  --filter "SEARCH('keyword',{Description})>0"

# Exclude archived records
airtable list myBase Contacts \
  --filter "NOT({Archived})"

Piping and Automation

Chain commands together:

# Export to JSON file
airtable list myBase Contacts --all --json > contacts.json

# Pipe to jq for processing
airtable list myBase Contacts --json | jq '.records[].fields.Email'

# Create from stdin
cat new-contacts.json | airtable create myBase Contacts --file -

# Delete with confirmation
airtable list myBase Contacts --filter "{Status}='Archived'" --json | \
  jq -r '.records[].id' | \
  xargs airtable delete myBase Contacts --force

Pagination

Handle large datasets:

# Get first page (100 records)
airtable list myBase Contacts --max 100

# Get next page using offset
airtable list myBase Contacts --max 100 --offset "itrXxxx"

# Fetch all records with automatic pagination
airtable list myBase Contacts --all

Batch Operations

Efficiently handle multiple records:

# Create 50 records (automatically batched in groups of 10)
airtable create myBase Contacts --file large-batch.json

# Upsert with smart merging
airtable upsert myBase Contacts --merge-on Email --file updates.json

# Delete multiple records
airtable delete myBase Contacts rec1 rec2 rec3 rec4 rec5 --force

Dry-Run Mode

Preview changes before committing:

# Preview creation
airtable create myBase Contacts --file records.json --dry-run

# Preview updates
airtable update myBase Contacts recXxxx --file changes.json --dry-run

# Preview deletion
airtable delete myBase Contacts recXxxx --dry-run

# Preview upsert
airtable upsert myBase Contacts --merge-on Email --file records.json --dry-run

Configuration Files

Configuration is stored in ~/.config/airtable-cli/config.json:

{
  "token": "pat_xxxxx",
  "defaultBase": "appXxxx",
  "aliases": {
    "myBase": "appXxxx",
    "staging": "appYyyy"
  }
}

Precedence

Token resolution order (first match wins):

  1. --token command-line option
  2. AIRTABLE_TOKEN environment variable
  3. token in config file
  4. Error: no token found

Base ID resolution order:

  1. Literal base ID (appXxxx)
  2. Alias from config (myBase → appXxxx)
  3. defaultBase from config
  4. Error: could not resolve base

Error Handling

The CLI provides clear error messages and exit codes:

# Exit codes
0   # Success
1   # General error
2   # Invalid usage
3   # Authentication failure (no token)
4   # Not found (base/table/record)
5   # Rate limit exceeded (429)
6   # Server error (5xx)

Authentication

Personal Access Token (Recommended)

  1. Go to airtable.com/create/tokens
  2. Click "Create new token"
  3. Name your token (e.g., "CLI")
  4. Add scopes:
    • data.records:read - Read records
    • data.records:write - Create/update records
  5. Add access to specific bases
  6. Generate token
  7. Store securely:
    export AIRTABLE_TOKEN="pat_xxxxx"
    # OR
    airtable config set token "pat_xxxxx"

API Key (Deprecated)

API keys are deprecated as of February 2024. Use Personal Access Tokens instead.

Rate Limiting

Airtable enforces rate limits:

  • Base-level: 5 requests/second
  • User-level (PAT): 50 requests/second
  • Batch limit: 10 records per request (automatic batching)

The CLI respects these limits. On 429 errors, wait 30 seconds before retrying.

Requirements

  • Node.js: 18.0.0 or later
  • npm: 8.0.0 or later
  • Airtable Account: With Personal Access Token

Development

# Install dependencies
npm install

# Build TypeScript
npm run build

# Watch for changes
npm run dev

# Run tests
npm test

# Type check
npm run typecheck

# Lint
npm run lint

Project Structure

src/
├── cli.ts              # Main CLI entry point
├── client.ts           # Airtable API client
├── config.ts           # Configuration management
├── output.ts           # Output formatting
├── types.ts            # TypeScript type definitions
└── commands/
    ├── records.ts      # Record CRUD commands
    ├── schema.ts       # Schema inspection commands
    └── config.ts       # Configuration commands

License

MIT

Support

For issues, feature requests, or contributions, visit the repository.


Tip: Use airtable --help and airtable <command> --help to see available options for any command.