Skip to content

Add "Export as bundle": parameterized DAB export for cross-workspace promotion - #233

Open
arnavc wants to merge 2 commits into
databricks-solutions:mainfrom
arnavc:feature/export-space-as-dab
Open

Add "Export as bundle": parameterized DAB export for cross-workspace promotion#233
arnavc wants to merge 2 commits into
databricks-solutions:mainfrom
arnavc:feature/export-space-as-dab

Conversation

@arnavc

@arnavc arnavc commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Adds an Export as bundle action to the Space detail view that downloads a
Genie space as a parameterized Databricks Asset Bundle (.zip). Every table
reference is rewritten to ${var.catalog}.${var.schema}.<table>, so the same
space definition can be deployed to another workspace by overriding the target's
variables.

This is the GitOps / cross-workspace promotion story for Genie spaces: author and
iterate in Workbench, then export a versionable, deployable bundle.

Opening as a draft to gather direction/feedback before investing further
see "Open questions" below.

What it does

Clicking Export as bundle opens a dialog:

  • Leave the prod fields blank → a dev-only bundle (a code backup of the space,
    with a dev target pointing at the current workspace).
  • Fill in prod host / catalog / schema / warehouse → the bundle also gets a
    prod target, making it deployable to that workspace with
    databricks bundle deploy -t prod.

The bundle contains databricks.yml (variables + dev/prod targets), an inlined
resources/<key>.genie_space.yml (the parameterized space), and a README.md
with deploy steps.

Why inline serialized_space (the core technical choice)

databricks bundle generate genie-space emits the space to an external
file_path: JSON. DAB variables (${var.x}) do not interpolate inside a
file_path-referenced JSON
— only inside config written directly in the YAML.
So this exporter inlines the definition under serialized_space: and tokenizes
the catalog/schema there, which is what makes parameterization actually resolve at
deploy time across all sections (data sources, example SQL, join specs, benchmarks).

Changes (additive; +658 / −5 across 4 files)

File Change
backend/services/bundle_exporter.py New. Pure transform (serialized_space dict → {path: contents}); prefix detection + recursive parameterization. No Databricks calls, no new deps (uses yaml).
backend/routers/spaces.py New endpoint GET /api/spaces/{id}/export-bundle (OBO fetch → parameterize → stream zip). Optional prod_* query params.
frontend/src/lib/api.ts exportSpaceBundle() helper (binary download + optional prod target).
frontend/src/pages/SpaceDetail.tsx "Export as bundle" button + prod-target dialog (uses existing AlertDialog/Input).

The 5 removed lines are import statements extended in place — all prior symbols
retained. No existing endpoint, function, dependency, or auth path is modified.

Scope / boundary (by design)

Workbench runs in one workspace via OBO, which cannot cross workspace boundaries.
So this generates the bundle; the user deploys it to the target workspace
with their own credentials (databricks auth login + bundle deploy -t prod).
Cross-workspace deploy is intentionally out of the app.

Testing

  • Frontend npm run build (typecheck + Vite) passes.
  • Deployed to a live Databricks App; exported a real space, deployed the resulting
    bundle to a second workspace, and confirmed the deployed space resolves 100% to
    the target catalog/schema and answers live Genie queries.

Open questions for maintainers

  1. Prod-target capture — is the in-dialog prompt the right UX, or should this
    integrate with a saved "environments" concept?
  2. Deploy facilitation — should Workbench stop at the artifact (current), or
    grow a Git-commit / CI-trigger path (deploy via a CI service principal)?
  3. Target readiness — the bundle parameterizes references but doesn't create
    target tables; worth a pre-deploy catalog/schema/table check?
  4. Multi-catalog spaces — currently parameterizes the dominant prefix and warns
    on others; is full multi-prefix mapping in scope?

This pull request and its description were written by Isaac and tested end to end extensively by Arnav.

arnavc added 2 commits June 15, 2026 01:16
Export a Genie space as a parameterized Databricks Asset Bundle:
- backend/services/bundle_exporter.py: pure transform (serialized_space dict
  -> {path: contents}); auto-detects the source catalog.schema prefix and
  rewrites every reference to ${var.catalog}.${var.schema} across data
  sources, example SQL, join specs, and benchmarks.
- GET /api/spaces/{id}/export-bundle: fetches the space via OBO, runs the
  exporter, streams a .zip (databricks.yml + resources/*.genie_space.yml +
  README). Optional prod_* query params add a promotion target.
- SpaceDetail: 'Export as bundle' button + api.ts blob-download helper.

Verified the transform produces serialized_space byte-identical to a
hand-built bundle that deployed and validated on a real workspace.

Co-authored-by: Isaac
The export endpoint already accepted optional prod_host/prod_catalog/
prod_schema/prod_warehouse_id query params, but the UI never sent them, so
the generated bundle was always dev-only. This wires up a dialog that
collects the four prod-target fields when the user clicks 'Export as bundle':

- api.ts: exportSpaceBundle() now takes an optional ExportProdTarget and
  forwards the four values as query params.
- SpaceDetail.tsx: the button opens a dialog (repo's AlertDialog + Input)
  instead of exporting immediately. Prod fields are all-or-nothing — fill all
  four to bake a deployable prod target into databricks.yml, or leave them
  blank for a dev-only bundle (a code backup). The dialog notes that Workbench
  cannot deploy across a workspace boundary; the user deploys the bundle with
  their own prod credentials.

Frontend build + typecheck pass.

Co-authored-by: Isaac
@arnavc
arnavc marked this pull request as ready for review June 24, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant