| name | fabric-cicd |
| description | Use for the fabric-cicd Python library (`pip install fabric-cicd`, v1.3 Aug 2026, Python 3.9–3.13) — Microsoft's official code-first CI/CD library for Fabric workspaces: `FabricWorkspace`, `publish_all_items`, `unpublish_all_orphan_items`, `deploy_with_config` + config.yml, and `parameter.yml` (find_replace, key_value_replace, spark_pool, semantic_model_binding, $workspace/$items dynamic vars, $ENV:, _ALL_, regex, extend). Covers the explicit-TokenCredential requirement (v1.0 breaking change), feature flags (enable_lakehouse_unpublish, enable_bulk_publish, enable_shortcut_publish, enable_hard_delete, include/exclude), per-item-type caveats (Warehouse/SQL DB, Lakehouse, Variable Library), Azure DevOps / GitHub Actions + OIDC, Fabric notebook usage, and troubleshooting (change_log_level, FABRIC_CICD_FILE_LOGGING_ENABLED, configure_fabric_fqdn). Invoke when the user mentions fabric-cicd, FabricWorkspace, publish_all_items, parameter.yml, or code-first Fabric deployment from Git. |
fabric-cicd (Python deployment library)
Microsoft's official open-source Python library for code-first CI/CD into Fabric workspaces. It abstracts the Fabric REST item-definition APIs: point it at a Git checkout of a Fabric Git-synced workspace folder and it publishes every in-scope item into the target workspace.
Version / install: current is v1.3.x (August 2026). pip install fabric-cicd (or uv add fabric-cicd). Python 3.9–3.13. Docs: microsoft.github.io/fabric-cicd · repo: github.com/microsoft/fabric-cicd.
v1.0 (April 2026) was a breaking release: token_credential became required — the DefaultAzureCredential fallback and implicit Fabric-notebook auth were removed. Any pre-1.0 sample that omits the credential no longer runs.
Which deployment surface am I on?
| Surface | Source of truth | When |
|---|
| fabric-cicd (this skill) | Git | Python-scripted deploys in ADO / GitHub Actions / notebooks; finest control (feature flags, orphan cleanup, selective publish) |
fab deploy --config config.yml | Git | Same engine, CLI wrapper — one-command deploys; see fabric-cli skill |
| Fabric deployment pipelines (service-side) | Workspace | Dev workspace promoted stage-to-stage in the portal / REST; no local code involved |
fab deploy wraps fabric-cicd and consumes the same config.yml / parameter.yml. Don't mix Git-driven deploys and service-side deployment pipelines on the same workspaces. Decision guide: Choose the best Fabric CI/CD workflow.
Deployment model
- Full deployment every run — no commit-diff inspection. The target workspace converges to the repository state; drift is overwritten. (
get_changed_items(repository_directory, git_compare_ref="HEAD~1") exists if you want to scope a run yourself.)
- Source layout = what Fabric Git integration writes:
<item-name>.<ItemType>/ folders (plus optional workspace subfolders) and an optional parameter.yml / config.yml at the repository-directory root. Don't hand-craft item folders — commit them from the portal.
- Only item types with source-control + public-API support are deployable (34 types as of v1.3).
- Deploys into the tenant of the executing identity.
Quick start
from azure.identity import AzureCliCredential
from fabric_cicd import FabricWorkspace, publish_all_items, unpublish_all_orphan_items
workspace = FabricWorkspace(
workspace_id="<target-workspace-guid>",
environment="PROD",
repository_directory="<path-to-workspace-folder>",
item_type_in_scope=["Notebook", "DataPipeline", "Environment"],
token_credential=AzureCliCredential(),
)
publish_all_items(workspace)
unpublish_all_orphan_items(workspace)
Core API
FabricWorkspace(*, repository_directory, token_credential,
item_type_in_scope=None, environment="N/A",
workspace_id=None, workspace_name=None)
publish_all_items(ws, item_name_exclude_regex=None,
folder_path_exclude_regex=None, folder_path_to_include=None,
items_to_include=None,
shortcut_exclude_regex=None)
unpublish_all_orphan_items(ws, item_name_exclude_regex="^$",
items_to_include=None)
deploy_with_config(config_file_path, *, token_credential,
environment="N/A", config_override=None)
append_feature_flag(flag) / remove_feature_flag(flag) / get_supported_feature_flags()
change_log_level("DEBUG")
configure_fabric_fqdn(workspace_id)
get_changed_items(repository_directory, git_compare_ref="HEAD~1")
The selective-publish parameters (items_to_include, folder_path_*, shortcut_exclude_regex) require their experimental feature flags (below) or they're ignored.
Authentication
Pass any azure.identity TokenCredential:
| Context | Credential |
|---|
| Local dev | AzureCliCredential() / AzurePowerShellCredential() |
| ADO / GitHub SPN | ClientSecretCredential(client_id=..., client_secret=..., tenant_id=...) |
| OIDC / federated | WorkloadIdentityCredential() |
| Self-hosted agent / Azure VM | ManagedIdentityCredential() |
| Fabric notebook | custom wrapper below |
Running inside a Fabric notebook (implicit auth was removed):
import time
from azure.core.credentials import TokenCredential, AccessToken
class FabricNotebookCredential(TokenCredential):
def get_token(self, *scopes, **kwargs):
return AccessToken(notebookutils.credentials.getToken("pbi"), int(time.time()) + 3600)
The identity needs Contributor+ on the target workspace (Admin for enable_hard_delete). SPNs additionally need the tenant setting Service principals can use Fabric APIs — same prerequisites as any Fabric REST automation (see fabric-auth skill).
parameter.yml
Environment-specific value substitution applied to file contents at publish time, keyed by the environment passed to FabricWorkspace. Lives at the repository-directory root.
find_replace — string / regex replacement
find_replace:
- find_value: "123e4567-e89b-12d3-a456-426614174000"
replace_value:
PPE: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
PROD: "9b2e5f4c-8d3a-4f1b-9c3e-2d5b6e4a7f8c"
item_type: "Notebook"
item_name: ["Hello World"]
file_path: "**/notebook-content.py"
Optional: is_regex: "true" (then find_value is a regex; capture group 1 is what gets replaced — include surrounding context in the pattern), ignore_case: "true".
- find_value: \#\s*META\s+"default_lakehouse":\s*"([0-9a-fA-F-]{36})"
replace_value:
_ALL_: "$items.Lakehouse.Example_LH.$id"
is_regex: "true"
item_type: "Notebook"
key_value_replace — JSONPath-targeted replacement
key_value_replace:
- find_key: $.properties.activities[?(@.name=="Load_Intake")].typeProperties.source.datasetSettings.externalReferences.connection
replace_value:
PPE: "6c517159-d27a-41d5-b71e-ca1ecff6542b"
PROD: "0f2ef3d1-1f34-4e0e-9483-6c8dbc077514"
item_type: "DataPipeline"
spark_pool — Environment-item pool remapping
spark_pool:
- instance_pool_id: "72c68dbc-0775-4d59-909d-a47896f4573b"
replace_value:
PPE: { type: "Capacity", name: "CapacityPool_Medium" }
PROD: { type: "Capacity", name: "CapacityPool_Large" }
semantic_model_binding — post-deploy connection binding
semantic_model_binding:
default:
connection_id:
_ALL_: "<connection-guid>"
models:
- semantic_model_name: "Sales Model"
connection_id:
PPE: "<guid>"
PROD: "<guid>"
Dynamic replacement variables
Usable in replace_value (not combinable with is_regex):
| Variable | Resolves to |
|---|
$workspace.$id / $workspace.$name / $workspace.$name_encoded | Target workspace id / name / URL-encoded name |
$workspace.<name>.$id | Another workspace's id by name |
$items.<Type>.<name>.$id | Deployed item's id (type/name case-sensitive, attribute lowercase) |
$items.<Type>.<name>.$sqlendpoint | Lakehouse / Warehouse / MirroredDatabase / SQLDatabase connection string |
$items.<Type>.<name>.$sqlendpointid | Lakehouse / MirroredDatabase endpoint id |
$items.Eventhouse.<name>.$queryserviceuri | Eventhouse query URI |
Other mechanics
_ALL_ env key = same replacement for every environment.
$ENV:var_name in replace_value reads a pipeline/OS environment variable — requires the enable_environment_variable_replacement feature flag.
extend: — list of relative paths to split parameter files into templates.
- Validation runs automatically at deploy start (deployment halts on failure); pre-validate with
devtools/debug_parameterization.py.
- Dynamic variables disable bulk publish mode, and using any of them triggers eager SQL-endpoint resolution for all Lakehouses/Warehouses in the target workspace.
Config-file deployment (deploy_with_config)
Single-call deployment driven by a config.yml — the same file fab deploy consumes. Every field accepts either a scalar (all envs) or a per-env mapping (dev: / test: / prod:).
core:
workspace_id:
dev: "8b6e2c7a-..."
prod: "7c3e1f8b-..."
repository_directory: "."
item_types_in_scope: [Notebook, DataPipeline, Environment, Lakehouse]
parameter: "parameter.yml"
publish:
exclude_regex: "^DONT_DEPLOY.*"
folder_exclude_regex: { dev: "^/DONT_DEPLOY_FOLDER" }
folder_path_to_include: { prod: ["/DEPLOY_FOLDER"] }
items_to_include: ["Hello World.Notebook"]
skip: { dev: true, test: false, prod: false }
unpublish:
exclude_regex: "^DEBUG.*"
skip: { prod: true }
features:
- enable_shortcut_publish
constants:
DEFAULT_API_ROOT_URL: "https://api.fabric.microsoft.com"
deploy_with_config("config.yml", token_credential=cred, environment="prod",
config_override={"publish": {"skip": {"prod": False}}})
Feature flags (append_feature_flag)
| Flag | Effect |
|---|
enable_lakehouse_unpublish / enable_warehouse_unpublish / enable_sqldatabase_unpublish / enable_eventhouse_unpublish / enable_kqldatabase_unpublish | Allow orphan deletion of data-bearing items — off by default as data-loss protection |
enable_hard_delete | Bypass workspace recycle bin on unpublish; requires workspace Admin |
enable_shortcut_publish / continue_on_shortcut_failure | Deploy Lakehouse shortcuts / tolerate shortcut failures |
disable_workspace_folder_publish | Don't create workspace subfolders |
enable_environment_variable_replacement | Activate $ENV: in parameter.yml |
enable_response_collection | publish_all_items returns collected API responses |
enable_experimental_features + enable_bulk_publish | Single bulk-import API call instead of per-item (beta; non-prod) |
enable_experimental_features + enable_items_to_include / enable_exclude_folder / enable_include_folder / enable_shortcut_exclude | Activate the selective-publish parameters |
Enumerate at runtime: get_supported_feature_flags().
Item-type caveats (the ones that bite)
- Warehouse / SQL Database: shell only — no tables/views/procs deployed. Pair with SqlPackage/dacpac for schema (see fabric-database skill).
- Lakehouse: shell + (flag-gated) shortcuts; schemas only deployed when a schema contains a shortcut. Deletion blocked unless
enable_lakehouse_unpublish.
- Notebook:
.py and .ipynb supported; attached-lakehouse GUIDs need parameterization (regex example above); notebook resources aren't source-controlled.
- Environment: custom pool references need the
spark_pool section; resources not source-controlled.
- Semantic Model / Report: use
semantic_model_binding for connections; report→model rebinding handled when both deploy together.
- Dataflow: same-workspace dependencies auto-ordered; first deployment still needs a manual publish/refresh.
- Variable Library: the active value set is selected by the
environment value — the deploy picks the value set matching the environment name.
- Eventhouse / KQL Database: parameterization not applied to these types; KQL table data not source-controlled.
- Data Pipeline / Copy Job / Mirrored Database / Paginated Report: connection references are not source-controlled — parameterize connection GUIDs (
key_value_replace on externalReferences.connection) and pre-create connections in the target.
- ML Experiment / Mounted Data Factory: shell only / requires the external ADF to exist.
Full 34-type matrix: reference/item_types.
Pipeline wiring (ADO / GitHub Actions)
Canonical pattern — auth step establishes an Azure context, then a plain Python step runs the deploy script: