There are two ways to stand Fabric up, depending on where you're running it. Both end the same way: open the UI, add a source, choose the tables, hit Start Replication, and data flows to Iceberg, Delta Lake, Postgres, S3 Tables, Snowflake, or ClickHouse — one SELECT away.
Local (one command)
To try the charts — what you actually run in production — without a build step, the repo ships a bootstrapper. It targets k3s if it's already installed and running on this machine, or falls back to a throwaway kind cluster otherwise (with a warning — see below), installs the two published images from GHCR, and runs helm upgrade --install on the same two charts the next section installs:
cli/fabric-cli local upcli/fabric-cli is a short launcher checked in beside the package: it runs the CLI through uv in this checkout's own project environment, so there is nothing to install — both charts and their values-local.yaml files come from the tree you cloned, and the images are the published ones. Working on the source itself, local up --build builds both images here and loads them into the cluster instead. Spelled out, that is uv run --project cli fabric local up.
It prints the UI URL and the local admin credentials once every Pod is Ready, and verifies the UI answers before it does. Runners are Pods on this install, exactly as in production (deployment):
cli/fabric-cli local status # releases, Pods, and the UI URL
cli/fabric-cli local credentials # UI URL and the admin login, read from the live Secret
cli/fabric-cli local logs -f # tail backend logs (--source <id> for one runner's Pod)
cli/fabric-cli local open # open the UI in your browser
cli/fabric-cli local down # uninstall the releases (and, on kind, the cluster)The command contains no product code. It is k3s/kind, helm, and kubectl invoked as documented, plus two values files checked in beside the charts: fabric-web/values-local.yaml and fabric-worker/values-local.yaml. Together they install two releases into one namespace — fabric-web (the API, UI, Celery beat, the migrations Job, and a laptop-sized Postgres and Redis, with no TLS and the UI reached through a NodePort) and fabric-worker (the Celery workers and the runner-fleet RBAC, with no Postgres or Redis of its own — it reads the web release's ConfigMap and Secret). up names both charts and the values file each is provisioned from before it installs, and asks one question — whether to pre-configure object storage. Answer no (the default) and the install seeds no destination, which is what a customer's install looks like: point destination.* at your own bucket. Answer yes and a MinIO is installed from deploy/local/minio.yaml and seeded as the default destination, for evaluation only.
k3s vs. kind
down never deletes it (only the releases). kind nests the cluster inside Docker/Podman containers — fine for a laptop, but a host reboot reassigns the node container's IP and strands the control plane (kind doesn't support restarting a cluster), and down deletes it along with the releases. For anything that needs to stay up on one box, install k3s first and this command uses it automatically — see Migrating from docker compose.Requirements
helm and kubectl on PATH — that is the whole list: the images are published to GHCR, so the cluster pulls them. kind is only needed when there's no active k3s to fall back to it, and docker or podman only for up --build, which builds both images from the checkout instead of pulling them.Kubernetes (Helm)
For production — or any footprint bigger than a laptop — Fabric ships as two Helm charts: fabric-web for the shared control plane and fabric-worker for the execution layer, installed into a cluster you already run.
helm install fabric-web fabric/fabric-web --namespace fabric --create-namespace \
--set database.host=my-postgres.example.com \
--set database.password=... \
--set fabric.secretKey=... \
--set fabric.adminPassword=... \
--set destination.warehouse=s3://my-bucket/warehouse/ \
--set destination.s3Endpoint=https://s3.us-east-1.amazonaws.com \
--set destination.s3AccessKeyId=AKIA... \
--set destination.s3SecretAccessKey=...
helm install fabric-worker fabric/fabric-worker --namespace fabric \
--set fabric.existingSecret=<secret-name>The worker release installs second, in the same namespace, with fabric.existingSecret naming the web release's Secret — the runner's env decryption key has to match the API's. Neither chart installs object storage: the warehouse and its credentials are yours to name, and the install fails with the missing key names rather than seeding a destination that cannot connect. Set destination.enabled=false instead to seed nothing and add destinations under Destinations in the UI. Redis is bundled by fabric-web (redis.enabled) and switches to a broker you already run when you turn it off. Resource requests/limits, storage classes, and volume sizes are all values, so a larger install is a values file, not a fork of the manifests.
What you need
ingress.enabled); a NodePort or LoadBalancer Service reaches the UI without one. See Deployment for the component list and the values that matter.