Task: Switch clouds with one line
You have a working data product on one cloud (say, local DuckDB) and you want to redeploy it on another (say, GCP BigQuery). The whole point of Forge's contract-first model is that this is a one-line YAML change + a re-apply.
Time: ~5 minutes assuming the target cloud is already credentialed.
What you start with
A working contract on the original cloud — for this task, a Bitcoin price tracker already running locally on DuckDB. (The GCP walkthrough builds this contract from scratch; here we start from the finished contract.fluid.yaml.)
fluid apply contract.fluid.yaml --yes
# ✓ Pipeline complete · runtime/out/bitcoin_prices.parquet
That produced a Parquet artifact via the local provider on DuckDB. Now we want the same product on BigQuery.
Step 1 — install the target provider
pip install "data-product-forge[gcp]"
fluid providers
# Lists: local ✓, gcp ✓
GCP credentials are picked up via Application Default Credentials (gcloud auth application-default login). No Forge-specific auth setup.
Step 2 — change one line in the contract
Open contract.fluid.yaml and find the binding block:
exposes:
- exposeId: bitcoin_prices
binding:
platform: local # ← change this
format: parquet
location:
path: ./runtime/out/bitcoin_prices.parquet
Change to:
exposes:
- exposeId: bitcoin_prices
binding:
platform: gcp # ← here
format: bigquery_table
location:
project: your-gcp-project
dataset: crypto
table: bitcoin_prices
region: europe-west3
Three keys move (platform, format, location). Everything else — schema, dq.rules, accessPolicy, agentPolicy, sovereignty — stays byte-identical. Confirm with git diff:
git diff contract.fluid.yaml
# - platform: local
# - format: parquet
# - location: { path: ./runtime/out/bitcoin_prices.parquet }
# + platform: gcp
# + format: bigquery_table
# + location: { project: your-gcp-project, dataset: crypto, table: bitcoin_prices, region: europe-west3 }
Step 3 — re-validate against the new platform
fluid validate contract.fluid.yaml
# ✓ Schema 0.7.2 — passed
# ✓ binding.platform=gcp — supported (provider gcp installed)
# ✓ binding.location complete (project, dataset, table)
# ✓ Contract validation passed
Step 4 — preview what will change
fluid plan contract.fluid.yaml --env prod
# Plan summary:
# + ensure dataset crypto (region=europe-west3)
# + create table crypto.bitcoin_prices
# + grant role/dataViewer (from accessPolicy.grants)
# + run build bitcoin_price_ingestion (sql)
The planner is deterministic — same contract + same deployed state = same plan. The plan is bound (cryptographically) to the next apply step (stage 6 → 7 of the canonical pipeline).
Step 5 — apply
fluid apply contract.fluid.yaml --env prod --yes
# ⏳ Acquiring lease on gold.crypto.bitcoin_tracker_v1...
# ⏳ Ensuring BigQuery dataset crypto...
# ✓ dataset crypto exists
# ⏳ Creating table crypto.bitcoin_prices...
# ✓ table crypto.bitcoin_prices created
# ⏳ Running bitcoin_price_ingestion (BigQuery SQL)...
# ✓ transformation complete (24 rows in)
# ⏳ Applying IAM bindings...
# ✓ BigQuery roles/dataViewer granted to group:analysts@company.com
# ✓ Pipeline complete in 4.83 s
The same data product is now on BigQuery. Same schema, same governance, same dq.rules.
Step 6 — verify against the deployed state
fluid verify contract.fluid.yaml --env prod --strict
# ✓ Schema matches deployed state
# ✓ accessPolicy.grants match BigQuery IAM bindings
# ✓ dq.rules satisfied (24 rows pass completeness)
# ✓ Verify passed
What happens if I want to switch again?
Same pattern — change binding.platform to aws (or snowflake), re-apply. The provider for the target cloud handles its own dialect/SDK quirks; the contract stays identical.
What you DIDN'T have to do
- Rewrite SQL for a new dialect (Forge handles dialect translation when
engine: sql; rare cases that genuinely need a hand-tuned dialect can useengine: dbtwith target-specific macros) - Re-author IAM in a new cloud's syntax (
accessPolicy.grants→ native IAM happens atpolicy-apply) - Re-write your Airflow DAG (
fluid generate schedule --scheduler airflowregenerates with the new platform) - Re-test quality rules (the same
dq.rulesblock runs against the new cloud's storage)
See also
- GCP walkthrough — full GCP-specific deployment guide
- Snowflake walkthrough — Snowflake team collaboration flow
- Providers vs platforms — how the abstraction works
- Same contract demo — frame-perfect cast of this exact swap on screen