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

bubble-io-cli

v4.6.1

Published

An open-source CLI for managing, backing up, and interacting with Bubble.io applications via the Data API

Readme

🫧 bubble-io-cli

A powerful, open-source command-line interface for developers and entrepreneurs who build with Bubble.io.

npm version License: MIT Node.js TypeScript Tests PRs Welcome


✨ What is bubble-io-cli?

bubble-io-cli brings your Bubble.io application to the terminal. Instead of navigating the Bubble dashboard to export data or manage configurations, you can now automate these workflows directly from the command line — perfect for CI/CD pipelines, scheduled backups, developer tooling, and no-code + code hybrid workflows.

# Launch the Interactive Terminal UI (TUI) — No complex arguments needed!
bubble-io-cli

# Or run direct commands:
# Configure credentials
bubble-io-cli config --app my-cool-app --key YOUR_BUBBLE_API_KEY

# Back up any data type instantly
bubble-io-cli backup --type Product --env version-live

# Generate a GitHub Actions workflow for nightly automated backups
bubble-io-cli generate ci --provider github

# Export Bubble data directly into a SQLite database
bubble-io-cli export db --type User --target sqlite --db ./bubble.db

# Compare schema between environments
bubble-io-cli schema diff

# Generate database migrations declaratively (New in v4.4.0)
bubble-io-cli schema migrate:generate --name add_orders

# Use lifecycle hooks to auto-upload backups to S3 (New in v4.5.0)
# Place a plugin in ~/.bubble-cli/plugins/ — hooks fire automatically

# Start a local mock server for offline testing
bubble-io-cli mock --file ./backup-product.json --port 3333

🚀 Quick Start

Prerequisites

  • Node.js >= 18.0.0
  • A Bubble.io account with API access enabled
  • Your Bubble Private API Key (found in Settings → API → Private key)

Installation

# Install globally via npm
npm install -g bubble-io-cli

# Or use directly without installing
npx bubble-io-cli --help

🎮 Interactive Mode (TUI)

Don't want to remember command-line arguments and flags? Run bubble-io-cli with no arguments to launch the beautiful, interactive Terminal User Interface (TUI):

bubble-io-cli
┌  🫧  Bubble.io CLI — Interactive Mode
│
◇  Active Environment
│  Profile: default
│  App:     my-cool-app.bubbleapps.io
│  API Key: ********************1234
│
?  What would you like to do?
│  ● 📐 Schema Operations (List, Diff, ERD, Migrations & Snapshots)
│  ○ 💾 Data Operations (Backup, Restore, Diff, Seed, REPL Query, DB Export)
│  ○ 🧬 Code & Type Generation (TypeScript interfaces, Templates, CI/CD)
│  ○ 🛠️  Developer Tools (PII Audit, Health check, Mock server, Workflows)
│  ○ ⚙️  Profiles & Credentials (Manage saved apps and API keys)
│  ○ ❌ Exit
└

Key Highlights of Interactive Mode

  • Zero-setup Discovery: Guided prompts for data types, environments (version-test vs version-live), output formats, and paths.
  • Smart Credential Management: Displays your active profile, subdomain, and masked API key on entry. If no profile exists, prompts to set one up on the spot.
  • Continuous Workflow: Automatically asks if you'd like to perform another action after completing a task without re-running the command.
  • Safe Exit & Cancellation: Press Ctrl+C or Esc at any prompt step to gracefully cancel without stack traces.

📖 Commands

config — Manage Credentials & Profiles

Store your Bubble app credentials securely in local OS config storage. Supports multiple named profiles so you can manage credentials for several Bubble apps simultaneously.

# Save credentials (default profile)
bubble-io-cli config --app my-cool-app --key YOUR_BUBBLE_API_KEY

# Save credentials under a named profile
bubble-io-cli config --app my-staging-app --key STAGING_KEY --profile staging

# List all stored profiles (shows active profile with ●)
bubble-io-cli config --list

# Switch the active profile
bubble-io-cli config --use staging

# View the current profile's configuration (key is masked)
bubble-io-cli config --show

# View a specific profile's configuration
bubble-io-cli config --show --profile staging

# Clear the current profile
bubble-io-cli config --clear

# Clear a specific profile
bubble-io-cli config --clear --profile staging

# Clear ALL profiles
bubble-io-cli config --clear --all

| Option | Alias | Description | |---|---|---| | --app <name> | -a | Your Bubble app subdomain | | --key <apiKey> | -k | Your private Bubble API key | | --profile <name> | -p | Named profile to save/load | | --show | | Display the current config | | --list | | List all profiles | | --use <profile> | | Switch active profile | | --clear | | Clear current or named profile | | --all | | Combined with --clear: remove all profiles |


backup — Export Data

Download records from any Bubble data type and save them locally. Supports JSON and CSV output, server-side filtering, incremental exports, cloud upload, encryption, watch mode, and CI-friendly JSON output.

# Basic backup (test environment, all records)
bubble-io-cli backup --type Product

# Backup from production
bubble-io-cli backup --type User --env version-live

# Limit to first 100 records
bubble-io-cli backup --type Product --limit 100

# Export as CSV
bubble-io-cli backup --type Order --format csv

# Server-side filtering (Bubble constraints)
bubble-io-cli backup --type Order \
  --constraint '[{"key":"status","constraint_type":"equals","value":"active"}]'

# Incremental export — only records modified since a date
bubble-io-cli backup --type User --since 2026-08-01

# Watch mode — backup every hour automatically
bubble-io-cli backup --type Product --watch --interval 3600

# Upload to Amazon S3 after export
bubble-io-cli backup --type User --destination s3://my-bucket/backups

# Upload to Google Cloud Storage
bubble-io-cli backup --type User --destination gs://my-bucket/backups

# Encrypt the backup (AES-256-GCM)
export BUBBLE_BACKUP_PASSPHRASE="your-strong-passphrase"
bubble-io-cli backup --type Product --encrypt

# Send Slack / Discord notification on completion
bubble-io-cli backup --type Product \
  --notify-slack https://hooks.slack.com/services/T/B/secret \
  --notify-discord https://discord.com/api/webhooks/123/secret

# Machine-readable JSON output for CI/CD
bubble-io-cli backup --type Product --json

| Option | Alias | Description | Default | |---|---|---|---| | --type <datatype> | -t | Bubble data type (required) | — | | --env <environment> | -e | version-test or version-live | version-test | | --output <dir> | -o | Output directory | . | | --limit <number> | -l | Max records to fetch | all | | --format <type> | -f | json or csv | json | | --constraint <json> | -c | Bubble constraint JSON array | — | | --since <date> | | Export only records modified after date | — | | --watch | | Continuous backup mode | — | | --interval <seconds> | | Watch interval (min 10s) | 3600 | | --destination <url> | | Cloud upload: s3:// or gs:// | — | | --encrypt | | AES-256-GCM encryption | — | | --notify-slack <url> | | Slack Incoming Webhook URL | — | | --notify-discord <url> | | Discord Webhook URL | — | | --notify-on-error | | Also notify on failures | — | | --json | | Machine-readable JSON output | — |

Cloud upload: Requires npm install @aws-sdk/client-s3 (for S3) or npm install @google-cloud/storage (for GCS), loaded lazily.

Encryption: Reads passphrase from BUBBLE_BACKUP_PASSPHRASE env var. Output file uses .enc extension.


restore — Upload Records to Bubble

Bulk-upload records from a local backup file back to Bubble via the Data API.

# Restore to test environment
bubble-io-cli restore --file ./backup-product-2026-08-07.json

# Restore with upsert mode (create new + update existing by _id)
bubble-io-cli restore --file ./backup-user.json --mode upsert

# Preview what would be restored (no API calls)
bubble-io-cli restore --file ./backup-product.json --dry-run

# Control parallelism
bubble-io-cli restore --file ./backup-order.json --concurrency 10

| Option | Alias | Description | Default | |---|---|---|---| | --file <path> | -f | Backup JSON file (required) | — | | --env <environment> | -e | Target environment | version-test | | --type <datatype> | -t | Override data type from file | — | | --mode <mode> | -m | create or upsert | create | | --concurrency <n> | | Parallel API requests (1–20) | 5 | | --dry-run | | Simulate without API calls | — |


diff — Compare Data

Compare live Bubble data against a local backup file and show exactly what changed.

# Compare Product type with a local backup (full table fetch)
bubble-io-cli diff --file ./backup-product-2026-08-07.json

# ⚡ Fast mode: only fetch the specific record IDs from the backup
# Best for large tables — no full table scan, no extra Capacity Units consumed
bubble-io-cli diff --file ./backup-user.json --local-only

# Limit the number of remote records fetched (useful for spot-checking)
bubble-io-cli diff --file ./backup-product.json --limit 500

# Compare specific fields only
bubble-io-cli diff --file ./backup-user.json --fields name,email,plan

# Show summary counts only (no per-record details)
bubble-io-cli diff --file ./backup-order.json --summary

# Combine --local-only with --summary for a quick health check
bubble-io-cli diff --file ./backup-user.json --local-only --summary

| Option | Alias | Description | Default | |---|---|---|---| | --file <path> | -f | Local backup file (required) | — | | --type <datatype> | -t | Override the data type | — | | --env <environment> | -e | Target environment | version-test | | --fields <list> | | Comma-separated fields to compare | all | | --limit <number> | -l | Cap the number of records fetched from Bubble | all | | --local-only | | Only fetch the specific IDs from the backup — much faster for large tables | — | | --summary | | Show counts only, no per-record detail | — |

--local-only trade-off: This mode queries Bubble only for the record IDs already present in the backup file (in chunks of 50), making it extremely fast and capacity-efficient. However, it cannot detect records that were added to Bubble after the backup was taken. Use the default (full fetch) or --limit when you need to detect new records too.

--local-only and --limit are mutually exclusive — the CLI will exit with an error if both are specified together.


health — Check API Connectivity

Verify that your credentials are valid and your Bubble app is reachable.

# Check test environment
bubble-io-cli health

# Check both environments at once
bubble-io-cli health --all

# Check production
bubble-io-cli health --env version-live

# Machine-readable output for CI
bubble-io-cli health --json

| Option | Alias | Description | Default | |---|---|---|---| | --env <environment> | -e | Environment to check | version-test | | --all | | Test both environments | — | | --type <datatype> | -t | Data type to ping | User | | --json | | JSON output | — |


schema list — Inspect App Schema

List all data types and their field definitions using the Bubble Meta API.

Requires: Enable "Expose Data API" and "Expose schema" in Bubble → Settings → API.

# List all data types
bubble-io-cli schema list

# Show fields for all types
bubble-io-cli schema list --fields

# Inspect a specific type
bubble-io-cli schema list --type Product

# Export schema as JSON
bubble-io-cli schema list --json

schema diff — Compare Schema Between Environments

# Compare test vs live schema (default)
bubble-io-cli schema diff

# Custom environments
bubble-io-cli schema diff --env-a version-test --env-b version-live

# JSON output for CI comparison
bubble-io-cli schema diff --json

Output is color-coded: + green (added), - red (removed), ~ yellow (changed), at the field level.


schema erd — Generate Entity-Relationship Diagram

Generate a Mermaid.js Entity-Relationship Diagram from your Bubble schema. It automatically detects relationships between your data types.

# Print Mermaid ERD to the terminal
bubble-io-cli schema erd

# Save directly to a markdown file (renders in GitHub/VS Code)
bubble-io-cli schema erd --output ./erd.md

# Include Bubble built-in types (User, FileObject, etc.)
bubble-io-cli schema erd --include-system-types

# Print raw Mermaid code block only (useful for piping)
bubble-io-cli schema erd --raw

schema migrate:generate — Schema-as-Code Database Migrations (New in v4.4.0)

Capture, track, and version control your Bubble.io database schema evolution declaratively.

  • Generates timestamped JSON migration files in ./migrations/<timestamp>_<name>.json
  • Supports 5 discrete declarative operations: ADD_TABLE, REMOVE_TABLE, ADD_FIELD, REMOVE_FIELD, and CHANGE_FIELD_TYPE
  • Tracks the local baseline state using migrations/schema.lock.json
  • Supports direct environment diffing between version-live and version-test (--from-env)
# Initialize baseline schema snapshot (creates migrations/schema.lock.json)
bubble-io-cli schema migrate:generate --snapshot-only

# Generate a migration tracking changes against the local lockfile baseline
bubble-io-cli schema migrate:generate --name add_phone_and_status --description "Add phone and status fields to User"

# Compare test directly against production without modifying the local lockfile
bubble-io-cli schema migrate:generate --name sync_prod_to_test --from-env version-live --env version-test

# Specify custom migrations directory
bubble-io-cli schema migrate:generate --name add_orders --dir ./custom-migrations

# Output migration result as JSON for CI/CD automation
bubble-io-cli schema migrate:generate --name ci_check --json

Migration File Example (migrations/20260808224500_add_phone_and_status.json):

{
  "version": "20260808224500",
  "name": "add_phone_and_status",
  "description": "Add phone and status fields to User",
  "createdAt": "2026-08-08T22:45:00.000Z",
  "app": "my-cool-app",
  "environment": "version-test",
  "changes": [
    {
      "action": "ADD_FIELD",
      "table": "User",
      "field": "phone_number",
      "type": "text"
    },
    {
      "action": "CHANGE_FIELD_TYPE",
      "table": "Product",
      "field": "price",
      "previousType": "text",
      "type": "number"
    }
  ]
}

schema migrate:list — Inspect Migration History (New in v4.4.0)

Display all recorded migration files and inspect the current schema lockfile baseline:

# View formatted terminal table of migrations
bubble-io-cli schema migrate:list

# Custom directory
bubble-io-cli schema migrate:list --dir ./custom-migrations

# Machine-readable JSON output
bubble-io-cli schema migrate:list --json

workflow trigger — Trigger Backend Workflows

Call Bubble backend workflows that have "This workflow can be triggered by API" enabled.

# Trigger a workflow
bubble-io-cli workflow trigger --name send-invoice

# Trigger with inline parameters
bubble-io-cli workflow trigger --name process-order --data '{"orderId":"abc123"}'

# Trigger with a complex payload from a file (recommended for Windows)
bubble-io-cli workflow trigger --name process-order --data @payload.json

# Trigger on production
bubble-io-cli workflow trigger --name daily-report --env version-live

# JSON output for scripting
bubble-io-cli workflow trigger --name send-invoice --json

| Option | Alias | Description | Default | |---|---|---|---| | --name <workflowName> | -n | API name of the workflow (required) | — | | --env <environment> | -e | Target environment | version-live | | --data <json> | -d | JSON object of workflow parameters | — | | --json | | Machine-readable output | — |


seed — Populate Test Data

Bulk-create records in Bubble from a local JSON fixture file. Ideal for seeding test environments.

# Seed from a fixture file
bubble-io-cli seed --file ./seeds/products.json

# Preview without creating anything
bubble-io-cli seed --file ./seeds/users.json --dry-run

# Control parallelism
bubble-io-cli seed --file ./seeds/orders.json --concurrency 10

Seed file format:

{
  "type": "Product",
  "records": [
    { "name": "Widget", "price": 9.99 },
    { "name": "Gadget", "price": 24.99 }
  ]
}

mock — Local Mock Server

Start a local Express HTTP server that exposes a Bubble-compatible Data API from a backup JSON file. Perfect for offline development and integration testing.

# Start mock server on default port 3333
bubble-io-cli mock --file ./backup-product.json

# Custom port
bubble-io-cli mock --file ./backup-user.json --port 4000

# Enable CORS (for browser-based testing)
bubble-io-cli mock --file ./backup-product.json --cors

# Load multiple data types at once
bubble-io-cli mock --file Product=./backup-product.json --file User=./backup-user.json

Available endpoints once server is running:

| Method | Path | Description | |---|---|---| | GET | /api/1.1/obj/:type?cursor=0&limit=100 | Paginated list | | GET | /api/1.1/obj/:type/:id | Single record | | POST | /api/1.1/obj/:type | Create (in-memory) | | PATCH | /api/1.1/obj/:type/:id | Update (in-memory) | | DELETE | /api/1.1/obj/:type/:id | Delete (in-memory) | | GET | /health | Server status and loaded types |


plugin — Plugin Editor API

Manage Bubble plugins via the Plugin Editor API.

Requires: BUBBLE_PLUGIN_TOKEN environment variable.
Get your token: Bubble Editor → Plugins → Plugin Editor → Settings → API token

export BUBBLE_PLUGIN_TOKEN="your-plugin-editor-token"

# List all plugins
bubble-io-cli plugin list

# Get a specific plugin's full definition
bubble-io-cli plugin get <pluginId>

# Deploy a plugin definition (create new)
bubble-io-cli plugin deploy --file ./plugin.json

# Update an existing plugin
bubble-io-cli plugin deploy --file ./plugin.json --id existing-plugin-id

# Preview without making API calls
bubble-io-cli plugin deploy --file ./plugin.json --dry-run

generate — Scaffold Templates & TypeScript Types

Generate boilerplate TypeScript files for common Bubble integration patterns, or automatically create TypeScript interface definitions from your live Bubble schema.

generate types — TypeScript Interface Generator (New in v3.0.0)

Connects to the Bubble Meta API and generates clean, fully-typed TypeScript interfaces for your data types — perfect for building type-safe integrations and SDKs.

# Preview all interfaces to stdout
bubble-io-cli generate types

# Export all data types to a single declaration file
bubble-io-cli generate types --output ./src/bubble-types.d.ts

# Export only a single data type
bubble-io-cli generate types --type Product --output ./src/types/product.d.ts

# Target the production environment
bubble-io-cli generate types --env version-live --output ./src/bubble-types.d.ts

# Use a named credential profile
bubble-io-cli generate types --profile staging --output ./src/bubble-types.d.ts

Example output for a Product type with mixed fields:

/**
 * Auto-generated by bubble-io-cli v3.0.0
 * App: my-cool-app | Environment: version-test
 * Generated: 2026-08-07T22:00:00.000Z
 *
 * DO NOT EDIT — regenerate with: bubble-io-cli generate types
 */

export interface Product {
  /** Unique Bubble record identifier */
  _id: string;
  /** ISO 8601 creation timestamp */
  'Creation Date': string;
  /** ISO 8601 last modification timestamp */
  'Modified Date': string;
  /** [text] */
  Name?: string;
  /** [number] */
  Price?: number;
  /** [boolean] */
  'Is Active'?: boolean;
  /** [date] */
  'Launch Date'?: string;
  /** [Category] relationship → stored as Bubble ID */
  Category?: string;
  /** [list of text] */
  Tags?: string[];
}

Bubble → TypeScript type mapping:

| Bubble type | TypeScript type | Notes | |---|---|---| | text | string | | | number | number | | | boolean | boolean | | | date | string | ISO 8601 string (Bubble returns dates as strings) | | geographic address | BubbleGeographicAddress | Helper interface auto-emitted | | file, image, option | string | URL or string value | | list of text/number/... | string[], number[], ... | | | list of <CustomType> | string[] | Bubble stores lists as ID arrays | | Custom data type | string | Relationship → stored as Bubble ID |

| Option | Alias | Description | Default | |---|---|---|---| | --env <environment> | -e | version-test or version-live | version-test | | --profile <name> | -p | Named profile to use | active profile | | --type <name> | -t | Generate only this data type | all types | | --output <file> | -o | Write to file (omit for stdout) | stdout |


generate — Scaffold Integration Templates

# List available templates
bubble-io-cli generate --list

# Scaffold a plugin server-side action
bubble-io-cli generate --template plugin-action --name SendEmail

# Scaffold a CRUD API connector for a data type
bubble-io-cli generate --template api-connector --name Product

# Scaffold a webhook receiver for Bubble data triggers
bubble-io-cli generate --template data-trigger --name OrderCreated --output ./webhooks

| Template | Description | |---|---| | plugin-action | Typed Bubble plugin server-side action scaffold | | api-connector | Full CRUD connector class for a Bubble data type | | data-trigger | HTTP webhook receiver for Bubble data change events |


generate ci — CI/CD Pipeline Generator (New in v4.0.0, Enhanced in v4.5.0)

Generate a production-ready GitHub Actions or GitLab CI workflow file that automatically backs up your Bubble data every night. One command, zero manual YAML editing.

# Generate with all defaults (backs up User type, runs at 03:00 UTC, 30-day retention)
bubble-io-cli generate ci --provider github

# Generate for multiple types (uses matrix strategy to run in parallel)
bubble-io-cli generate ci --provider github --type User,Product,Order

# Generate a GitLab CI pipeline
bubble-io-cli generate ci --provider gitlab --type User,Product

# Customize for a specific type, schedule, and retention period
bubble-io-cli generate ci --provider github \
  --type User \
  --env version-live \
  --cron "0 1 * * *" \
  --retention 14 \
  --format json

# Preview what would be generated without writing to disk
bubble-io-cli generate ci --provider gitlab --type Product --format csv --dry-run --cli-version 4.0.0 \
  --output .github/workflows

# Export to CSV instead of JSON
bubble-io-cli generate ci --provider github --type Product --format csv

What the generated workflow does:

  1. ✅ Runs on a nightly cron schedule (configurable)
  2. ✅ Supports workflow_dispatch for manual on-demand runs
  3. ✅ Installs bubble-io-cli from npm (latest or pinned version)
  4. ✅ Configures credentials securely from GitHub Secrets
  5. ✅ Runs bubble-io-cli backup --json and validates the result
  6. ✅ Uploads the backup as a GitHub Actions Artifact (configurable retention)
  7. ✅ Writes a rich summary table to the GitHub Actions UI

Required GitHub Secrets (add under Settings → Secrets → Actions):

| Secret | Description | |---|---| | BUBBLE_APP_NAME | Your Bubble app subdomain (e.g. my-app) | | BUBBLE_API_KEY | Your Bubble private Data API key |

| Option | Alias | Description | Default | |---|---|---|---| | --provider <name> | | CI/CD provider: github | required | | --type <datatype> | -t | Bubble data type to back up | User | | --env <environment> | -e | Bubble environment | version-live | | --cron <expression> | | UTC cron schedule expression | 0 3 * * * | | --retention <days> | | Artifact retention days (1–90) | 30 | | --format <type> | -f | Backup format: json or csv | json | | --cli-version <version> | | npm version to pin | latest | | --output <dir> | -o | Output directory | .github/workflows |


query — Interactive REPL (New in v3.1.0)

Start a fully interactive terminal session to search, filter, and browse Bubble records in real time — without leaving the CLI.

# Start interactive query session (test environment)
bubble-io-cli query

# Target the live environment
bubble-io-cli query --env version-live

# Use a named profile with custom page size
bubble-io-cli query --profile staging --page-size 10

Interactive session flow:

🫧  bubble-io-cli Interactive Query
   App: my-cool-app  |  Env: version-test

  Select a data type:
    1) User
    2) Product
    3) Order
  > 2

  [Product] Quick options:
    f) Add / change text search
    c) Add / change field constraint
    x) Clear all filters
    t) Change data type
    q) Quit
    Enter) Fetch records (current filters)
  > f

  Search in "Name": widget

  ┌──────────────────────────┬──────────────┬───────┬──────────────────────────────┐
  │ _id                      │ Name         │ Price │ Creation Date                │
  ├──────────────────────────┼──────────────┼───────┼──────────────────────────────┤
  │ 1723031234567x123456789  │ Widget       │ 9.99  │ 2026-08-01T10:00:00.000Z     │
  │ 1723031234568x987654321  │ Widget Pro   │ 19.99 │ 2026-08-02T11:00:00.000Z     │
  └──────────────────────────┴──────────────┴───────┴──────────────────────────────┘

  Showing 2 records  |  Page 1 of 1  |  Total: 2

  Actions:
    r) Refine / change filters
    t) Change data type
    e) Export current page to JSON
    q) Quit
  > e

  ✅ Exported 2 record(s) → query-export-Product-2026-08-07T22-00-00-000Z.json

Supported constraint operators: equals, not equal, text contains, greater than, less than, is_empty, is_not_empty

| Option | Alias | Description | Default | |---|---|---|---| | --env <environment> | -e | version-test or version-live | version-test | | --profile <name> | -p | Named credential profile | active profile | | --page-size <n> | | Records per page (max: 100) | 20 |

Tip: Use Ctrl+C at any time to exit the session gracefully.


audit privacy — PII & Privacy Security Audit (New in v3.2.0)

Scan your Bubble schema or a local backup file for potentially exposed Personally Identifiable Information (PII) and security risks. The scanner detects high-risk field names across 8 categories and outputs a color-coded report with Bubble Privacy Rule recommendations.

# Scan your live remote schema (requires credentials)
bubble-io-cli audit privacy

# Scan a local backup JSON file
bubble-io-cli audit privacy --file ./backup-user-2026-08-07.json

# Scan only a specific data type
bubble-io-cli audit privacy --type User

# Only show CRITICAL and HIGH findings
bubble-io-cli audit privacy --min-risk HIGH

# Target the production environment
bubble-io-cli audit privacy --env version-live

# JSON output for CI pipelines
bubble-io-cli audit privacy --json

Example terminal output:

🔍 Privacy Audit Report — my-app [version-test]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  source: remote schema   scanned: 8 types · 54 fields
  Findings: 2 CRITICAL · 3 HIGH · 1 MEDIUM

  ──────────────────────────────────────────────────────────

  🔴 CRITICAL — User.password_hash [text]
     ⚠ Field name matches credential pattern ("password"). Exposing this field risks account takeover.
     💡 In Bubble Privacy Rules: set this field to "No one" access. Never expose credentials via the Data API.

  🔴 CRITICAL — User.api_token [text]
     ⚠ Field name matches credential pattern ("token"). Exposing this field risks account takeover.
     💡 In Bubble Privacy Rules: set this field to "No one" access.

  🟠 HIGH — User.email [text]
     ⚠ Field name matches personal contact information ("email"). PII exposure risk.
     💡 In Bubble Privacy Rules: restrict to "This User" and explicitly granted roles only.

  📋 Next Steps:
     1. Open Bubble Editor → Data → Privacy
     2. For each CRITICAL finding — set the field to "No one" access
     3. For each HIGH finding — restrict to authenticated users or "This User"

Detection categories:

| Risk | Category | Example field names | |---|---|---| | 🔴 CRITICAL | Credentials | password, token, api_key, secret, auth_token | | 🔴 CRITICAL | Financial | credit_card, ssn, iban, bank_account, cvv | | 🟠 HIGH | Government ID | passport, national_id, driver_license | | 🟠 HIGH | Biometric | fingerprint, face_id, biometric | | 🟠 HIGH | Contact PII | email, phone, address, date_of_birth | | 🟠 HIGH | Medical | diagnosis, medical, patient, prescription | | 🟡 MEDIUM | Geolocation | gps, latitude, longitude, coordinates | | 🟡 MEDIUM | Demographics | full_name, salary, gender, ethnicity |

CI Integration: The command exits with code 1 when CRITICAL findings are detected — use it as a security gate in GitHub Actions.

| Option | Description | Default | |---|---|---| | --file <path> | Scan a local backup JSON file | — | | --env <env> | Target Bubble environment | version-test | | --type <name> | Scan only a specific data type | all types | | --min-risk <level> | Minimum severity: MEDIUM, HIGH, CRITICAL | MEDIUM | | --json | Machine-readable JSON output | false | | --profile <name> | Named credential profile | active |


export db — Export to Database (New in v4.0.0)

Export records from any Bubble data type directly into an external database. Supports SQLite (zero-config, local), PostgreSQL, and BigQuery (enterprise). Uses a provider pattern — heavy database SDKs are loaded lazily, so installing the full CLI stays lean.

# ── SQLite — zero config, local file, no extra dependencies ──────────────────
bubble-io-cli export db --type User --target sqlite --db ./bubble.db

# Export a specific type to a named file
bubble-io-cli export db --type Product --target sqlite --db ./products.db

# Limit the number of records exported
bubble-io-cli export db --type Order --target sqlite --db ./orders.db --limit 500

# ── PostgreSQL — requires: npm install pg ─────────────────────────────────────
bubble-io-cli export db --type User \
  --target postgres \
  --connection-string "postgresql://user:pass@localhost:5432/mydb"

# Export from live environment
bubble-io-cli export db --type Product \
  --target postgres \
  --env version-live \
  --connection-string "postgresql://user:[email protected]/prod"

# ── BigQuery — requires: npm install @google-cloud/bigquery ──────────────────
# Uses Application Default Credentials (gcloud auth application-default login)
bubble-io-cli export db --type Order \
  --target bigquery \
  --project my-gcp-project \
  --dataset bubble_data

# With a service account key file
bubble-io-cli export db --type User \
  --target bigquery \
  --project my-gcp-project \
  --dataset bubble_data \
  --key-file ./service-account.json

How it works:

  1. Fetches all records from Bubble via the Data API (with cursor pagination)
  2. Connects to the target database
  3. Creates the table automatically if it doesn't exist (schema inferred from the first record)
  4. Adds any new columns that appear in subsequent records (ALTER TABLE)
  5. Upserts all records idempotently — safe to re-run, no duplicates

Optional dependencies (installed only when needed):

| Target | Install command | Notes | |---|---|---| | sqlite | (included — uses sql.js) | Pure JavaScript, no native compilation | | postgres | npm install pg | Also: npm install -D @types/pg for TypeScript | | bigquery | npm install @google-cloud/bigquery | Uses ADC or --key-file |

SQLite — what gets created:

A .db file with one table per Bubble data type. Table name = sanitized type name (e.g. Useruser). All fields are stored with inferred types (TEXT, REAL, INTEGER). JSON objects/arrays are stored as JSON strings.

BigQuery — table naming convention:

Table names are prefixed with bubble_ (e.g. Orderbubble_order) to avoid conflicts with existing BQ tables. Streaming inserts use _id as insertId for best-effort deduplication.

| Option | Alias | Description | Default | |---|---|---|---| | --type <datatype> | -t | Bubble data type to export (required) | — | | --target <provider> | | sqlite | postgres | bigquery (required) | — | | --env <environment> | -e | Bubble environment | version-test | | --limit <number> | -l | Maximum records to export | all | | --profile <name> | -p | Named credential profile | active | | --db <path> | | SQLite .db file path | ./bubble.db | | --connection-string <url> | | PostgreSQL connection string | — | | --project <id> | | GCP project ID (BigQuery) | — | | --dataset <id> | | BigQuery dataset ID | bubble_data | | --key-file <path> | | Service account key JSON file | — |


seed — Relational Data Import (New in v4.1.0)

Import records into Bubble from a local JSON file. Supports two formats:

Legacy Format (single data type)

bubble-io-cli seed --file seeds/products.json
bubble-io-cli seed --file seeds/users.json --type User --env version-test
bubble-io-cli seed --file seeds/orders.json --dry-run

Legacy seed file structure:

{
  "type": "Product",
  "records": [
    { "Name": "Widget Pro", "Price": 29.99 },
    { "Name": "Widget Lite", "Price": 9.99 }
  ]
}

Relational Format (multi-type with cross-references)

Import entire interconnected datasets in a single command. Use _ref aliases to define cross-links between records — the CLI handles creation order automatically via a dependency graph engine.

bubble-io-cli seed --file seeds/catalog.json
bubble-io-cli seed --file seeds/catalog.json --dry-run   # preview the execution plan
bubble-io-cli seed --file seeds/catalog.json --json      # machine-readable output

Relational seed file structure:

{
  "Category": [
    { "_ref": "@cat_tech", "Name": "Technology" },
    { "_ref": "@cat_laptops", "Name": "Laptops", "Parent": "@cat_tech" }
  ],
  "Product": [
    {
      "_ref": "@prod_macbook",
      "Name": "MacBook Pro M3",
      "Category": "@cat_laptops",
      "Available_Sizes": ["@size_14", "@size_16"]
    }
  ],
  "Size": [
    { "_ref": "@size_14", "Name": "14 inch", "Product": "@prod_macbook" },
    { "_ref": "@size_16", "Name": "16 inch", "Product": "@prod_macbook" }
  ],
  "Price": [
    { "Amount": 1999, "Currency": "USD", "Product": "@prod_macbook", "Size": "@size_14" },
    { "Amount": 2499, "Currency": "USD", "Product": "@prod_macbook", "Size": "@size_16" }
  ]
}

How the _ref / @alias system works:

  • _ref assigns a temporary local alias to a record (e.g. "_ref": "@prod_macbook"). It is never sent to Bubble.
  • Any field value starting with @ is treated as a cross-reference and replaced at runtime with the real Bubble _id of the aliased record.
  • Arrays of references are fully supported: "Sizes": ["@size_14", "@size_16"].

Graph resolution capabilities:

| Scenario | Supported | |---|---| | N-level deep dependencies (A→B→C→…→N) | ✅ Unlimited depth | | Array / List of references | ✅ ["@ref1", "@ref2"] | | Self-referencing hierarchies (e.g. Category tree) | ✅ Auto-detected | | Circular dependencies (A↔B) | ✅ 2-pass: Create + deferred PATCH | | Unknown @ref alias | ✅ Fails fast with clear error before any API calls | | Duplicate _ref aliases | ✅ Fails fast with clear error before any API calls | | Atomic rollback on error | ✅ Reverse cleanup with --rollback-on-error | | Live schema validation | ✅ Type + field + relational type-check with --check-schema |

Tip: Always run with --dry-run first to preview the full creation order. Use --check-schema to validate types and fields against the live Bubble schema before any data is written. Combine both for a zero-risk dry validation:

bubble-io-cli seed --file catalog.json --check-schema --dry-run

Options:

| Option | Short | Description | Default | |---|---|---|---| | --file <path> | -f | Path to seed JSON file (required) | — | | --type <datatype> | -t | Override data type (legacy format only) | from file | | --env <env> | -e | Target environment | version-test | | --check-schema | | Validate all types and fields against the live Bubble schema before seeding | false | | --rollback-on-error | | Automatically delete created records in reverse order if any error occurs | false | | --concurrency <n> | | Parallel requests (legacy mode only, 1–20) | 5 | | --dry-run | | Preview execution plan without API calls | false | | --json | | Machine-readable JSON output | false | | --profile <name> | -p | Named credential profile | active |

--check-schema validation rules:

| Check | Severity | Description | |---|---|---| | Missing Type | ❌ Error | Type in seed does not exist in Bubble — aborts seed | | Missing Field | ❌ Error | Field in seed does not exist on the Bubble type — aborts seed | | Wrong Thing link | ⚠ Warning | A @ref value points to type A but the Bubble field expects type B | | Wrong list of Thing | ⚠ Warning | An array of @refs points to type A but Bubble field is list of B | | Number → text field | ⚠ Warning | A JS number is sent to a Bubble text field | | Boolean → text field | ⚠ Warning | A JS boolean is sent to a Bubble text field |


completions — Shell Tab Completion

Generate tab-completion scripts for Bash, Zsh, or Fish.

# Bash (add to ~/.bashrc)
source <(bubble-io-cli completions --bash)

# Zsh (add to ~/.zshrc)
source <(bubble-io-cli completions --zsh)

# Fish (run once)
bubble-io-cli completions --fish > ~/.config/fish/completions/bubble-io-cli.fish

🏗️ Architecture

bubble-io-cli/
├── src/
│   ├── index.ts                   # CLI entry point — registers all commands
│   ├── cli/                       # Interactive Terminal UI (TUI)
│   │   └── interactive.ts         # @clack/prompts interactive menu and sub-menu flows
│   ├── commands/                  # Command definitions (CLI Layer)
│   │   ├── config.ts              # config — credential storage
│   │   ├── backup.ts              # backup — export records
│   │   ├── restore.ts             # restore — upload records
│   │   ├── diff.ts                # diff — compare local vs remote
│   │   ├── health.ts              # health — ping API
│   │   ├── schema.ts              # schema list / diff / erd / migrate:generate / migrate:list
│   │   ├── workflow.ts            # workflow trigger — backend workflows
│   │   ├── seed.ts                # seed — relational import & graph execution
│   │   ├── mock.ts                # mock — local API server
│   │   ├── plugin.ts              # plugin list / get / deploy
│   │   ├── generate.ts            # generate (templates) / generate types / generate ci
│   │   ├── export.ts              # export db — database export (SQLite/PostgreSQL/BigQuery)
│   │   ├── audit.ts               # audit privacy — PII scanner
│   │   └── completions.ts         # completions — shell tab completion
│   ├── services/                  # Business logic
│   │   ├── bubble-api.ts          # BubbleApiClient — Data API (CRUD + pagination)
│   │   ├── bubble-meta.ts         # BubbleMetaClient — Meta API (schema)
│   │   ├── bubble-plugin.ts       # BubblePluginClient — Plugin Editor API
│   │   └── db-providers/          # Database export providers (provider pattern)
│   │       ├── index.ts           #   DbProvider interface + getDbProvider() factory
│   │       ├── sqlite.ts          #   SQLite provider (sql.js, zero native deps)
│   │       ├── postgres.ts        #   PostgreSQL provider (dynamic import: pg)
│   │       └── bigquery.ts        #   BigQuery provider (dynamic import: @google-cloud/bigquery)
│   └── utils/                     # Infrastructure helpers
│       ├── storage.ts             # Configstore — config & multi-profile
│       ├── csv.ts                 # CSV serialization (flattenRecord + jsonToCsv)
│       ├── encryption.ts          # AES-256-GCM encrypt/decrypt
│       ├── cloud-upload.ts        # S3 + GCS upload adapters
│       ├── notifications.ts       # Slack + Discord webhook dispatcher
│       ├── pii-scanner.ts         # PII detection engine
│       ├── plugin-loader.ts       # Plugin auto-discovery & registration
│       ├── plugin-manager.ts      # Lifecycle hook registry (PluginManager singleton)
│       ├── graph-resolver.ts      # DAG builder, topological sort, circular dep detection
│       ├── relational-seeder.ts   # Sequential execution engine for relational imports
│       ├── schema-preflight.ts    # Schema pre-flight validator for seed files
│       ├── schema-diff.ts         # Schema diffing engine
│       ├── schema-migrations.ts   # Schema-as-Code & migration engine
│       ├── schema-erd.ts          # Mermaid ERD generator
│       ├── type-generator.ts      # TypeScript interface generator
│       ├── table-renderer.ts      # cli-table3 table renderer
│       ├── query-session.ts       # REPL session state machine
│       └── ci-generators/
│           └── github-actions.ts  # GitHub Actions YAML generator
│
└── tests/                         # Vitest unit tests (321 tests)
    ├── plugin-manager.test.ts
    ├── schema-migrations.test.ts
    ├── interactive.test.ts
    ├── schema-preflight.test.ts
    ├── relational-seeder.test.ts
    ├── type-generator.test.ts
    ├── pii-scanner.test.ts
    └── ...

Separation of concerns: Command files handle only UX (spinners, colors, exit codes). All business logic lives in services/ and utils/.


🌍 Environment Variables

| Variable | Used by | Description | |---|---|---| | BUBBLE_BACKUP_PASSPHRASE | backup --encrypt | Passphrase for AES-256-GCM backup encryption | | BUBBLE_PLUGIN_TOKEN | plugin commands | Bubble Plugin Editor API token | | AWS_ACCESS_KEY_ID | backup --destination s3:// | AWS credentials for S3 upload | | AWS_SECRET_ACCESS_KEY | backup --destination s3:// | AWS credentials for S3 upload | | AWS_REGION | backup --destination s3:// | AWS region for S3 upload | | GOOGLE_APPLICATION_CREDENTIALS | backup --destination gs:// | GCP service account JSON path | | S3_BACKUP_BUCKET | plugin-s3-backup example | Target S3 bucket for auto-upload plugin | | SLACK_WEBHOOK_URL | plugin-slack-notifier example | Slack Incoming Webhook URL for notifications plugin |


🛠️ Development

# Clone the repository
git clone https://github.com/alexandrmotologa/bubble-io-cli.git
cd bubble-io-cli

# Install dependencies
npm install

# Run in development mode (tsx, no build step)
npm run dev -- config --show

# Build the production bundle
npm run build

# Run tests
npm test

# Type check only
npm run lint

🔌 Plugin Extensibility (v4.5.0+)

bubble-io-cli supports a powerful plugin system that lets you extend the CLI in two ways:

  1. Custom Commands — Add entirely new commands to the CLI via register(program)
  2. Lifecycle Hooks — React to events from existing commands without modifying core code

Available Lifecycle Hooks

| Hook | Fires when | |---|---| | init | CLI starts, after all plugins load | | beforeBackup / afterBackup | Before/after backup command | | beforeRestore / afterRestore | Before/after restore command | | onSchemaFetch | After schema list / schema diff / schema erd | | onSchemaDiff | After diff is computed in schema diff | | beforeExport / afterExport | Before/after export db command |

Install a Community Plugin

# Install any npm package named bubble-io-cli-plugin-*
npm install -g bubble-io-cli-plugin-example

# The plugin is automatically discovered on next CLI run
bubble-io-cli plugin ext list

Write a Hook Plugin in 60 Seconds

mkdir -p ~/.bubble-cli/plugins

Create ~/.bubble-cli/plugins/my-logger.js:

module.exports = {
  name: 'my-logger',
  version: '1.0.0',
  description: 'Logs backup events to the console',
  register(_program) {},  // no custom commands needed
  hooks: {
    afterBackup(ctx) {
      console.log(`[my-logger] ✅ ${ctx.records} records backed up → ${ctx.filePath}`);
    },
    onSchemaDiff(ctx) {
      if (!ctx.diff.identical) {
        console.warn(`[my-logger] ⚠️ Schema changed between ${ctx.envA} and ${ctx.envB}`);
      }
    },
  },
};

Write a Custom Command Plugin

Create ~/.bubble-cli/plugins/hello.js:

module.exports = {
  name: 'hello',
  version: '1.0.0',
  description: 'My first plugin',
  register(program) {
    program.command('hello').description('Say hello!').action(() => {
      console.log('Hello from my plugin! 🎉');
    });
  },
};
bubble-io-cli hello
# → Hello from my plugin! 🎉

Manage Plugins

bubble-io-cli plugin ext list          # List all loaded plugins
bubble-io-cli plugin ext info <name>   # Show plugin details
bubble-io-cli plugin ext reload        # Force plugin re-discovery

Ready-to-use Examples

Check out the fully functional example plugins in the examples/ directory:

Write Your Own Plugin

→ See the full Plugin Authoring Guide for the complete interface spec, all hook context types, TypeScript template, publishing guide, Commander patterns, and more examples.


🤝 Contributing

Contributions are warmly welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feat/my-new-command
  3. Commit your changes: git commit -m 'feat: add my-new-command'
  4. Push to the branch: git push origin feat/my-new-command
  5. Open a Pull Request

Architecture guide: new commands go in src/commands/, new API logic in src/services/, utility helpers in src/utils/. See docs/architecture.md for the full design.


📝 License

Distributed under the MIT License. See LICENSE for more information.