Schema Migration Tool — Google Cloud Bigtable

bigtablechange YAML-based schema migrations with rollback, drift detection & CI/CD

Purpose-built for Cloud Bigtable schema lifecycle management. Versioned YAML scripts manage tables, column families, GC policies, and app profiles — with distributed locking, immutable audit log, GC policy advisor, hotspot detection, column registry, and multi-instance pipelines. Enterprise tier adds contract checks, live schema analysis, instance diff, capacity projections, and CI/CD dashboards. 23 CLI commands. No JVM, no XML.

bigtablechange — production deploy
$ bigtablechange contract check --profile prod --github-annotations
⚠ [B001] user_events/event — no GC policy (retains all versions)
→ Add: gc_policy: max_versions: 1 or max_age_days: 30
$ bigtablechange analyse --profile prod
✓ feature_flags 1 families 98/100
⚠ user_events 2 families 72/100 [B001] no GC policy
$ bigtablechange instance-diff --source staging --target prod
✖ [GC_POLICY_MISMATCH] user_events/event — BREAKING
source=max_age_days=90 target=none
$ bigtablechange deploy --profile prod --tag 1.2.0
[lock] acquired (ci-runner-07a3b1)
[RUN] V1.2.0__add_analytics_table.yaml 38ms
[RUN] R__retention_policies.yaml checksum changed
[SKIP] V1.1.0__create_users.yaml already applied
[notify] Slack → deploy_success
✓ dsi001-prod: run 2 | skip 1 | errors 0 | tag 1.2.0
$
23
CLI Commands
4
Script Types
9
Drift Categories
YAML
Script Format

📜
YAML Scripts
Declarative YAML defines tables, column families, GC policies, and app profiles. The filename is the version.
🔒
Distributed Lock
Advisory Bigtable row lock prevents concurrent deploys across all CI/CD runners and operators.
📋
Immutable Audit Log
Every deploy, rollback, script execution, and lock event written append-only. Full traceability.
↩️
Paired Rollback
Every V__ script pairs with a U__ undo script. Roll back any version individually or to a tag.
🔍
Drift Detection
Nine drift categories compare migration history against the live Bigtable instance — tables, families, GC policies, profiles, and column registry.
🚰
Multi-Instance Pipeline
Ordered deploy across dev → staging → prod with confirmation gates and automatic rollback on failure.
📇
Column Registry
Opt-in governance layer. Declare columns, types, and PII tags in YAML. Surfaces removals, type changes, and PII additions across migration versions.
📜
Contract Checks
Policy-as-code schema governance. GC policy mandates, naming conventions, PII retention rules. GitHub PR annotations. Exits 2 on failure.
📊
Schema Analyser
Live instance health scorer 0–100. GC coverage, naming, PII exposure, hotspot risk. Text, JSON, and Markdown output.
Instance Diff
Compare two live Bigtable instances schema-to-schema. BREAKING/WARNING/INFO severity. Exit 2 on GC policy mismatch — hard CI gate.
📈
Capacity Projections
OLS regression over monitor snapshots projects days until row count and storage thresholds are crossed.
🌱
Test Data Seeder
Schema-aware synthetic data with semantic column hints. Hash-prefix row keys avoid hotspots. Registry type-aware generation.
One tool. One history table. Tables, families, GC policies, app profiles, column registry, contracts, monitoring. All versioned and rollback-ready.

Protocol

How It Works

Every deploy follows a deterministic 8-step sequence. Scripts run in version order. Nothing runs twice unless you change it.

STEP 01

Assert Instance Exists

Connects to the target Bigtable instance and verifies it is reachable. Exits immediately with a clear error if the instance or project is missing.

STEP 02

Ensure History Tables

Creates bigtablechange_history, bigtablechange_lock, and bigtablechange_audit if they don't exist. Zero manual setup required.

STEP 03

Acquire Deploy Lock

Writes an advisory lock row using the instance's own Bigtable API. Identifies the holder by hostname and run UUID. Blocks concurrent deploys.

STEP 04

Load History

Reads all rows in the history table and builds the applied-version set using latest-row-per-script logic — correctly handles rollback-then-redeploy cycles.

STEP 05

Execute V__ Scripts

Applies pending versioned scripts in ascending semver order. Already-applied versions are automatically skipped — safe to re-run at any time.

STEP 06

Execute R__ & A__ Scripts

Repeatable scripts rerun when their MD5 checksum changes. Always scripts run unconditionally — for GC policy syncs and permission refreshes.

STEP 07

Record History & Audit

A SUCCESS or FAILED row is written to history for every script. Every deploy event is appended to the immutable audit log with run_id, timestamp, and operator.

STEP 08

Release Lock & Notify

The deploy lock row is deleted. Slack and webhook notifications fire on configurable events: deploy_success, deploy_failed, script_failed, rollback_success.

bigtablechange never creates instances or projects. The target Bigtable instance must be provisioned externally via Terraform or gcloud. Instance creation is an infrastructure concern — schema migration is bigtablechange's concern.

Script Format

Declarative YAML

Scripts declare the desired state of tables, column families, GC policies, and app profiles. The filename carries the version — no XML changelogs, no separate config.

V1.2.0__add_analytics_table.yaml
# tag: 1.2.0 # row_key: tenant#{tenant_id}#reverse_ts tables: - name: user_events column_families: - name: event gc_policy: max_age_days: 90 - name: meta gc_policy: max_versions: 3 - name: counters gc_policy: union: - max_versions: 1 - max_age_days: 30 app_profiles: - name: analytics-reader routing: multi_cluster allow_transactional_writes: false
U1.2.0__add_analytics_table.yaml — undo script
# Paired undo — runs on: bigtablechange rollback tables: - name: user_events # table will be deleted app_profiles: - name: analytics-reader # profile will be deleted

Four script types give you fine-grained control over when and how often scripts run. The type is encoded in the filename prefix — no extra config needed.

V

Versioned

Runs once in ascending semver order. Never re-runs. Creates tables, adds column families, declares app profiles.

V1.2.0__add_analytics_table.yaml
U

Undo

Paired rollback for a versioned script. Only runs on rollback. Deletes profiles first (reverse order), then tables — idempotent.

U1.2.0__add_analytics_table.yaml
R

Repeatable

Reruns on deploy when its MD5 checksum changes. Ideal for keeping GC policies in sync with policy-as-code definitions.

R__retention_policies.yaml
A

Always

Executes on every deploy unconditionally. For seed data, app profile refreshes, and operations that must always be current.

A__refresh_app_profiles.yaml

CLI — Core

Seven Core Commands

Deploy, rollback, validate, status, repair, audit, and baseline — the foundational layer for schema lifecycle management.

deploy
locked
Apply all pending migrations in semver order. Acquires distributed lock. Respects --tag fences for incremental releases. Records every script in history and audit log.
bigtablechange deploy --profile prod bigtablechange deploy --profile prod --tag 1.2.0 bigtablechange deploy --dry-run
rollback
undo scripts
Roll back applied migrations using paired U__ undo scripts. Deletes app profiles before tables. Supports rollback by tag, target version, or most-recent.
bigtablechange rollback --profile prod bigtablechange rollback --target-version 1.0.0 bigtablechange rollback --tag 1.2.0 --dry-run
validate
offline
Offline validation — YAML parse, required fields, name format, GC policy structure, routing constraints, duplicate versions, orphan undo scripts. No Bigtable connection.
bigtablechange validate bigtablechange validate --root-folder ./migrations # exits 0 on pass, 1 on any error
status
read-only
Show migration history for an instance. Displays version, tag, script path, status, and timestamp for each row — sorted newest-first.
bigtablechange status --profile prod bigtablechange status --tag 1.2.0 bigtablechange status --limit 20
repair
recovery
Recover from failed deployments or stuck locks. Force-release a lock held by a dead process. Mark FAILED scripts as REPAIRED so they retry on next deploy.
bigtablechange repair --list bigtablechange repair --release-lock bigtablechange repair --script V1.2.0__foo.yaml
audit
append-only
View the immutable audit log. Every deploy start, script execution, failure, rollback, lock event written and never updated. Filter by run ID or limit.
bigtablechange audit --profile prod bigtablechange audit --run-id abc123 bigtablechange audit --limit 50
baseline
introspect
Introspect a live Bigtable instance and generate a V0.0.0 baseline YAML script. Captures all tables, column families, GC policies, and app profiles — including compound GC rules.
bigtablechange baseline --profile prod bigtablechange baseline --baseline-version 0.0.0 bigtablechange baseline --output ./migrations

CLI — Features

Nine Feature Commands

Beyond the core lifecycle, bigtablechange ships nine purpose-built commands for drift detection, GC policy analysis, script scaffolding, pipeline orchestration, reporting, verification, hotspot analysis, and column registry governance.

drift
9 categories
Compare migration history against the live instance. Detects out-of-band changes across tables, column families, GC policies, and app profiles. Exits 1 on ERROR-severity findings.
bigtablechange drift --profile prod # TABLE_MISSING, FAMILY_EXTRA, # GC_POLICY_CHANGED, PROFILE_MISSING...
advise
GC advisor
GC policy linter + optional Cloud Monitoring cross-reference. Static analysis runs offline. Live analysis flags families with no GC policy under real write load.
bigtablechange advise --offline bigtablechange advise --profile prod bigtablechange advise --lookback-hours 48
generate
scaffold
Scaffold a V/U migration script pair with auto-incremented version. Four templates: table, profile, gc, mixed. Writes correct YAML structure and # tag: header.
bigtablechange generate "add analytics table" bigtablechange generate "add profile" --type profile bigtablechange generate "gc sync" --version 2.0.0
diff
read-only
Show pending migrations without executing anything. Shows PENDING, RERUN, ALWAYS, and SKIP status per script. Use --exit-code as a CI gate to fail if migrations are pending.
bigtablechange diff --profile prod bigtablechange diff --profile prod --tag 1.2.0 bigtablechange diff --exit-code
pipeline
multi-instance
Deploy to multiple Bigtable instances in order (dev→staging→prod). Per-stage confirmation gates, per-stage tag fences, and configurable failure handling: rollback, stop, or continue.
bigtablechange pipeline --profile prod # reads pipeline: section from bigtablechange.yml # on_failure: rollback | stop | continue
report
snapshot
Full instance snapshot in text, JSON, or Markdown. Includes live tables, column families, GC policies, pending migrations, lock status, and last deploy information.
bigtablechange report --profile prod bigtablechange report --format json --output report.json bigtablechange report --format markdown
verify
post-deploy
Post-deploy smoke check. Re-reads the live instance and confirms every table, column family, and app profile from the applied scripts actually exists. Exits 1 on any missing resource.
bigtablechange verify --profile prod bigtablechange verify --all # --all verifies full applied history
hotspot
row key linter
Offline row key pattern linter. Analyses table names in migration scripts for sequential timestamps, sequential IDs, low-cardinality prefixes, and undocumented row key designs.
bigtablechange hotspot bigtablechange hotspot --level WARN # add # row_key: comment to suppress
registry
column governance
Opt-in column registry for compliance and large-team visibility. Declare column names, types, and PII tags in YAML. Surfaces removals, type changes, and PII additions across versions. Fully offline — never touches the Bigtable instance.
bigtablechange registry # show all declared columns bigtablechange registry drift # detect cross-version changes bigtablechange registry audit # audit log (PII events)

CLI — Enterprise

Seven Enterprise Commands

Policy-as-code governance, live schema health scoring, instance comparison, capacity projections, monitoring snapshots, synthetic data seeding, and CI/CD analytics dashboards.

contract
ENTERPRISE
Policy-as-code schema governance. Enforces GC policy mandates, naming conventions, PII retention rules, and hotspot patterns against the live instance. GitHub PR annotations. Built-in rules B001–B010 plus custom rules. Exits 2 on failures.
bigtablechange contract init # generate starter file bigtablechange contract check --profile prod bigtablechange contract check --github-annotations
analyse
ENTERPRISE
Live schema health scorer 0–100 per table. Checks GC coverage, excessive version retention, long retention periods, naming conventions, PII exposure without GC, and hotspot-prone table names. Text, JSON, and Markdown output.
bigtablechange analyse --profile prod bigtablechange analyse --format json bigtablechange analyse --format markdown --output report.md
instance-diff
ENTERPRISE
Compare two live Bigtable instances schema-to-schema. Diffs tables, column families, GC policies, and app profile routing. BREAKING/WARNING/INFO severity. Use as a hard CI gate before prod promotions — exits 2 on GC policy mismatch.
bigtablechange instance-diff --source staging --target prod bigtablechange instance-diff --format markdown --output diff.md # exit 0=identical 1=differences 2=BREAKING
monitor
ENTERPRISE
Snapshot live table health: row count and storage from Cloud Monitoring, family count, and GC coverage. Flags missing GC policies, excessive families, and hotspot-risk table names. Writes to bigtablechange_monitor_snapshots for capacity projections.
bigtablechange monitor --profile prod bigtablechange monitor --table user_events --json bigtablechange monitor --no-snapshot # read-only
capacity
ENTERPRISE
Project data growth using OLS linear regression over monitor snapshot history. Shows days until row count and storage thresholds are crossed, with R² nonlinearity detection. Requires three or more prior monitor runs.
bigtablechange capacity --profile prod bigtablechange capacity --horizon 180 # 180-day window bigtablechange capacity --table events --verbose
seed
ENTERPRISE
Schema-aware synthetic data seeder. Reads the column registry for type-aware generation with semantic column name hints (email, phone, status, lat/lon, timestamps). Hash-prefix row keys avoid hotspots. Reproducible via --seed.
bigtablechange seed --profile dev --rows 10000 bigtablechange seed --table user_events --seed 42 bigtablechange seed --dry-run # preview without writing
dashboard
ENTERPRISE
Generate a self-contained HTML CI/CD analytics dashboard from migration history. Deploy success rate, p95 deploy time, daily activity chart, slowest scripts, most-failed scripts, and release tag timeline. No server — open in a browser or commit to a repo.
bigtablechange dashboard --profile prod bigtablechange dashboard --days 30 --output ./reports/dash.html # self-contained HTML, no server required

Configuration

Multi-Instance Profiles

A single profile can target multiple Bigtable instances with independent migration paths. Every command — deploy, rollback, status, drift, analyse, monitor — runs against each instance in sequence automatically.

bigtablechange.yml — multi-instance Form B
profiles: dev-multi: project_id: gcp-learning-app instance_id: dsi001: cluster_id: dsi001-c1 root_folder: ./migrations-dsi001 dsi001-analytics: cluster_id: dsi001-analytics-c1 root_folder: ./migrations-dsi001-analytics prod: project_id: gcp-learning-app instance_id: dsi001-prod: cluster_id: dsi001-prod-c1 root_folder: ./migrations-dsi001 dsi001-analytics-prod: cluster_id: dsi001-analytics-prod-c1 root_folder: ./migrations-dsi001-analytics
All commands work per-instance automatically
$ bigtablechange deploy --profile dev-multi ━━ INSTANCE gcp-learning-app/dsi001 ━━ [RUN] V1.2.0__user_profiles.yaml 42ms ━━ INSTANCE gcp-learning-app/dsi001-analytics ━━ [RUN] V1.0.0__event_stream.yaml 31ms # status, drift, monitor — all iterate automatically bigtablechange status --profile dev-multi bigtablechange drift --profile dev-multi bigtablechange monitor --profile dev-multi

Two forms — fully backward-compatible

Form A (original): instance_id: dsi001 — single instance, unchanged behaviour.

Form B (new): instance_id as a mapping — each key is an instance ID with its own cluster_id and root_folder. Each instance has an independent history table and tracks applied versions separately.

You can be at V1.3.0 on the serving instance and V1.0.0 on the analytics instance simultaneously. The pipeline respects multi-instance profiles — each stage deploys all instances in that profile.

Drift ignore lists: Suppress known-good warnings with --ignore-profiles default (Bigtable always creates a default profile before any migration runs) or set drift.ignore_profiles in bigtablechange.yml.

Drift Detection

Catch What Changed Without You

bigtablechange compares migration history against the live Bigtable instance. Nine drift categories cover tables, families, GC policies, app profiles, and column registry. Pair with the GC policy advisor for proactive analysis.

Nine drift categories

Drift detection builds the expected state from all currently-applied migrations, then compares against live instance data. Internal bigtablechange tables are always excluded from detection. Exits 1 on ERROR-severity drift.

TABLE_MISSING
Migration says table exists; instance doesn't
TABLE_EXTRA
Table in instance never declared in a migration
FAMILY_MISSING
Column family declared, absent from live table
FAMILY_EXTRA
Column family exists on table, not in any migration
GC_POLICY_CHANGED
Live GC policy differs from last declared value
PROFILE_MISSING
App profile declared, not found in instance
PROFILE_EXTRA
App profile in instance, not in any migration
PROFILE_ROUTING_CHANGED
Routing type changed outside of migrations
COLUMN_REGISTRY
Column removed, type changed, or PII annotation added/removed across migration versions

GC policy advisor

The advisor analyses every declared column family for common GC policy mistakes. Static analysis runs entirely offline. Live analysis cross-references write RPS and storage bytes from Cloud Monitoring to upgrade findings to actionable levels.

RuleLevelWhat it catches
NO_GC_POLICYWARNNo GC policy — cells retained indefinitely
HIGH_MAX_VERSIONSSUGGESTmax_versions > 10 is unusually high
LONG_MAX_AGESUGGESTmax_age_days > 365 — verify intentional
TRIVIAL_UNIONSUGGESTunion with fewer than 2 rules is pointless
NO_GC_HIGH_WRITEACTIONNo GC + write rate > 100 req/s (live)
NO_GC_MODERATE_WRITEWARNNo GC + write rate > 10 req/s or storage > 1GB
HIGH_VERSIONS_LARGEWARNmax_versions > 3 on table > 10GB (live)

Row Key Analysis

Hotspot Detection Before Deploy

bigtablechange hotspot is a fully offline row key pattern linter. It analyses table names in your migration scripts for naming patterns associated with write hotspots — before a single row is ever written.

FindingLevelTriggered byRisk
SEQUENTIAL_TIMESTAMPWARNevents, logs, metrics, audit, traces…All writes land on last tablet
SEQUENTIAL_IDWARNorders, invoices, transactions, payments…Sequential keys create write hotspot at tail
USER_PREFIXSUGGESTuser_profiles, accounts, members…High-traffic users concentrate load on one tablet
LOW_CARDINALITY_PREFIXSUGGESTstatus, type, category, region…Low-cardinality prefix partitions data unevenly
NO_ROW_KEY_COMMENTSUGGESTAny table with no # row_key: commentUndocumented row key makes review impossible

Document row keys, suppress findings

Add a # row_key: comment to any YAML script to document the intended key design and suppress the NO_ROW_KEY_COMMENT finding. The comment serves as living documentation for your team.

Every finding includes a concrete recommendation with example row key patterns that distribute load evenly. The --level flag filters output to a minimum severity — use --level WARN in CI to catch high-risk patterns while suppressing informational suggestions.

V1.0.0__create_events_table.yaml
# row_key: tenant#{tenant_id}#reverse_timestamp # Reverse timestamp avoids sequential write hotspot. # tenant# prefix ensures even distribution across tablets. tables: - name: user_events column_families: - name: event gc_policy: max_age_days: 90

Architecture

Everything Stored In Bigtable

No external dependencies. The history, lock, and audit tables live in the same Bigtable instance as the data being migrated — no Postgres, no Redis, no Cloud Spanner required.

History Table

bigtablechange_history

Row key: script_path#installed_on_iso

  • h:script — relative path
  • h:version — semver string
  • h:checksum — MD5 of YAML
  • h:status — SUCCESS / FAILED / ROLLED_BACK
  • h:execution_ms — wall-clock time
  • h:installed_by — operator hostname
  • h:tag — deploy fence tag
  • h:run_id — UUID linking all rows per run

Lock Table

bigtablechange_lock

Row key: global

The lock row contains the holder's identity (hostname:run_id_prefix), acquisition timestamp, and full run UUID.

On acquire, bigtablechange reads the row and checks if the run_id column belongs to the current process. If not, LockError is raised with the holder's identity.

repair --release-lock performs an unconditional delete of the lock row to recover from stuck locks left by dead processes.

Latest-Row Logic

Handles rollback-then-redeploy

The history table is append-only. bigtablechange reads all rows per script and examines only the most recent row to determine current state:

tables/V1.0.0 2026-01-10 SUCCESS ← deploy tables/V1.0.0 2026-01-11 ROLLED_BACK ← rollback tables/V1.0.0 2026-01-12 SUCCESS ← re-deploy current state = last row = SUCCESS → script IS applied, skip on next deploy

Orchestration

Multi-Instance Pipeline

Deploy to multiple Bigtable instances in a defined sequence — dev → staging → prod — with per-stage confirmation gates, tag fences, and automatic rollback of completed stages on failure.

🧪

dev

Deploys automatically. No confirmation gate. First stage validates the scripts against a real instance before any human review is needed.

🔶

staging

pause_before: true — operator must press Enter to continue. Per-stage tag fence can restrict to a subset of pending scripts.

🚀

prod

pause_before: true — second confirmation gate before production. on_failure: rollback reverses all completed stages in reverse order if this stage fails.

Configure on_failure per pipeline: rollback reverses completed stages in reverse order, stop halts and leaves completed stages in place, continue logs the failure and proceeds.

bigtablechange.yml — pipeline configuration
pipeline: on_failure: rollback stages: - name: dev profile: dev - name: staging profile: staging pause_before: true - name: prod profile: prod tag: 1.2.0 # per-stage fence pause_before: true

CI / CD

CI-Native Workflow

A complete GitHub Actions pipeline with Workload Identity Federation, pre-deploy analysis, post-deploy verification, and diff-based PR gates.

Step 01

validate + hotspot + registry drift

Offline checks on every PR. YAML parse, naming, GC policy structure, row key risk analysis, and column registry drift detection. Zero network calls.

auto on PR
Step 02

contract check

Policy-as-code gate against the live instance. GC mandates, naming conventions, PII retention. GitHub PR annotations. Exits 2 on contract failures — blocks merge.

auto on PR
Step 03

instance-diff + diff

Compare staging schema against prod before promoting. Exits 2 on BREAKING GC policy mismatch. Show pending scripts without executing via diff.

auto on main
Step 04

deploy + verify

Deploy with Workload Identity. Follow with verify to confirm every resource from the just-applied scripts actually exists in the live instance.

auto on main
Step 05

drift + monitor + dashboard

Post-deploy drift check confirms the live instance matches history. Monitor snapshot captures health metrics for capacity projections. Dashboard updated.

environment gate

Comparison

How bigtablechange Compares

The only tool with a Bigtable-native history table, YAML-based declarative scripts, GC policy advisor, row key hotspot detection, column registry, policy-as-code contracts, live schema health scoring, instance diff, capacity projections, and multi-instance pipeline — all 23 commands without a JVM or external database.

CapabilitybigtablechangeTerraformCustom ScriptsManual gcloud
Versioned migration history✓ In Bigtable⚠ DIY
Rollback with undo scripts⚠ destroy/apply⚠ DIY
Distributed deploy lock✓ Advisory
Immutable audit log
GC policy management✓ YAML + advisor✓ HCL⚠ DIY
GC policy advisor✓ + live metrics
App profile lifecycle⚠ DIY
Schema drift detection✓ 9 categories✓ plan
Row key hotspot linting✓ Offline
Column registry & PII audit✓ Opt-in
Multi-instance pipeline⚠ modules
Multi-instance profiles✓ Form B config⚠ workspaces
Post-deploy verification✓ verify
Policy-as-code contracts✓ Enterprise
Live schema health scoring✓ 0–100 / table
Instance diff (schema compare)✓ BREAKING/WARN✓ plan
Capacity projections (OLS)✓ Enterprise
Test data seeder✓ Schema-aware
CI/CD analytics dashboard✓ HTML, no server
Incremental tag fencing
No JVM / no external DB✓ Python only✓ Go binary⚠ varies

Installation

Get Started in Minutes

Python 3.8+. Authentication via Application Default Credentials, service account key, or the Bigtable emulator for local development.

📦

Install

pip or from package

pip install bigtablechange
⚙️

Configure

bigtablechange.yml

project_id: my-gcp-project root_folder: ./migrations column_registry: true profiles: prod: instance_id: my-prod-instance staging: instance_id: my-staging-instance dev: emulator_host: localhost:8086
✍️

First Script

V1.0.0__initial_tables.yaml

# tag: 1.0.0 tables: - name: users column_families: - name: profile gc_policy: max_versions: 1 - name: activity gc_policy: max_age_days: 365
🚀

Deploy

validate → advise → deploy → verify

bigtablechange validate bigtablechange hotspot --level WARN bigtablechange registry drift bigtablechange contract check --profile staging bigtablechange instance-diff --source staging --target prod bigtablechange deploy --profile prod bigtablechange verify --profile prod bigtablechange drift --profile prod --ignore-profiles default bigtablechange monitor --profile prod bigtablechange dashboard --profile prod