fabric-data-pipelines
fabric-data-pipelines is a Python library for authoring Microsoft Fabric data pipelines as code.
Microsoft Fabric pipelines are JSON definitions under the hood. Editing that JSON by hand is slow and brittle: activity payloads are deeply nested, dependency wiring is verbose, and expression strings are easy to break. This library lets you describe pipelines with typed Python objects and then generate the exact Fabric-compatible JSON or Git item folders that Fabric expects.
Full guides, API reference, and real-world examples live on the documentation site.
Who this is for
This package is designed for teams that want Microsoft Fabric pipelines to be:
- declared in Python instead of assembled in the UI or hand-written JSON
- reviewed and versioned in Git
- exported into Fabric's
*.DataPipelinefolder format - validated before deployment or commit
Typical users are data engineers, analytics engineers, and platform teams building repeatable ETL or orchestration flows in Fabric.
Why use it
- Typed activities instead of manually building nested Fabric payloads
- Readable dependency helpers like
.then(),.after(), and>> - Expression helpers for parameters, activity outputs, run metadata, and interpolation
- Import existing Fabric Git items or JSON, and generate Python with
fabric-data-pipelines codegen - First-class support for Fabric Git item folders, including
.platformand.schedules - Validation of dependency graphs before serialization
- An escape hatch via
RawActivitywhen Fabric supports something not modeled yet
What it helps you build
You can use fabric-data-pipelines to build:
- small pipelines such as
Wait -> Notebook - ETL orchestration with
Script,Copy,Lookup, andExecutePipeline - control-flow pipelines with
IfCondition,ForEach,Switch, andUntil - scheduled Fabric items ready for Git integration
Installation
pip install fabric-data-pipelines
# or
uv add fabric-data-pipelines
Requires Python 3.10+.
from fabric_data_pipelines import Pipeline, Wait, Notebook
Quickstart
Create a tiny pipeline in Python and export the JSON definition:
from fabric_data_pipelines import Notebook, Pipeline, Wait
wait = Wait(name="Wait_For_Upstream", wait_time_in_seconds=30)
transform = Notebook(
name="Transform_Silver_Sales",
notebook_id="00000000-0000-0000-0000-000000000002",
workspace_id="00000000-0000-0000-0000-000000000001",
)
wait.then(transform)
pipeline = Pipeline(
name="Daily_Silver_Sales_Transform",
activities=[wait, transform],
)
pipeline.save("daily_silver_sales_transform.json")
That produces a Fabric-compatible pipeline definition without manually assembling the underlying JSON.
Before / after
Hand-writing Fabric JSON means nested policies, dataset settings, and column mappings. The same landing truncate-and-copy in Python is compact; the generated definition is ~200 lines.
Python (see examples/landing_truncate_copy.py):
from fabric_data_pipelines import (
AzureSqlMITable,
ColumnMapping,
ColumnRef,
Copy,
ExternalReferences,
Pipeline,
Script,
ScriptBlock,
SqlMISink,
SqlMISource,
TabularTranslator,
TypeConversionSettings,
expr,
)
LANDING = expr.library_variable("Demo_ETL_Library_Landing")
SOURCE = expr.library_variable("Demo_ETL_Library_SourceDb")
COLUMNS = ["customer_id", "region", "segment", "updated_at"]
truncate = Script(
name="Truncate_Landing_customers",
database="Landing",
scripts=[
ScriptBlock(
text={"value": "TRUNCATE TABLE sales.customers", "type": "Expression"},
type="Query",
)
],
external_references=ExternalReferences(connection=LANDING),
)
copy = Copy(
name="Copy_customers_to_Landing",
source=SqlMISource(
sql_reader_query=SELECT_SQL,
dataset_settings=AzureSqlMITable(database="SourceDb", connection=SOURCE),
),
sink=SqlMISink(
write_behavior="insert",
dataset_settings=AzureSqlMITable(
database="Landing",
schema_name="sales",
table="customers",
connection=LANDING,
),
),
translator=TabularTranslator(
mappings=[
ColumnMapping(
source=ColumnRef(name=col, type="String", physical_type="nvarchar"),
sink=ColumnRef(name=col, type="String", physical_type="nvarchar"),
)
for col in COLUMNS
],
type_conversion=True,
type_conversion_settings=TypeConversionSettings(allow_data_truncation=True),
),
)
truncate.then(copy)
Generated Fabric JSON (excerpt of ~200 lines):
{
"properties": {
"activities": [
{
"name": "Truncate_Landing_customers",
"type": "Script",
"typeProperties": {
"database": "Landing",
"scripts": [
{
"text": { "value": "TRUNCATE TABLE sales.customers", "type": "Expression" },
"type": "Query"
}
]
},
"externalReferences": {
"connection": "@pipeline().libraryVariables.Demo_ETL_Library_Landing"
}
},
{
"name": "Copy_customers_to_Landing",
"type": "Copy",
"dependsOn": [
{ "activity": "Truncate_Landing_customers", "dependencyConditions": ["Succeeded"] }
],
"typeProperties": {
"source": { "type": "SqlMISource", "datasetSettings": { "...": "..." }, "sqlReaderQuery": "..." },
"sink": { "type": "SqlMISink", "datasetSettings": { "typeProperties": { "table": "customers", "schema": "sales" } } },
"translator": { "type": "TabularTranslator", "mappings": ["... 4 column mappings ..."] }
}
}
],
"libraryVariables": { "...": "..." }
}
}
Full generated payload: docs/snippets/before_after_pipeline.json.
Real-world examples
The examples/ folder contains pipelines that mirror common Fabric workloads:
| Example | Pattern |
|---|---|
daily_notebook_transform.py |
Wait → Notebook |
landing_truncate_copy.py |
Truncate + Sql MI Copy with column mappings |
scheduled_gold_refresh.py |
Weekly schedule + save_item() Git folder |
lakehouse_lookup_to_warehouse.py |
Lookup → SetVariable → Warehouse Copy |
parameterized_elt_controller.py |
ForEach + Switch + Dataflow / stored procedure |
etl_with_lock_pattern.py |
Lock acquire / retry / invoke child / release |
uv run python examples/landing_truncate_copy.py
uv run python examples/scheduled_gold_refresh.py
See the ETL Patterns guide for walkthroughs of each pattern.
How it fits into Fabric
This library supports two main output shapes:
1. Raw pipeline JSON
Use Pipeline.to_json() or Pipeline.save() when you want the pipeline definition itself.
json_text = pipeline.to_json()
pipeline.save("daily_load.json")
2. Fabric Git item folders
Use Pipeline.save_item() or save_workspace() when your repository is the source of truth and Fabric should consume item folders.
Fabric expects each pipeline item to live in a directory such as:
Gold_Finance_Metrics_Refresh.DataPipeline/
pipeline-content.json
.platform
.schedules
This package generates those files for you, including schedule configuration when present.
Commit the folders into a Git-connected Fabric workspace and sync — see Deploy to Fabric. For validate-on-PR / export-on-merge, see CI with GitHub Actions.
Migrate from Fabric UI / Git
Already have pipelines in the portal or a Git-synced *.DataPipeline/ folder? Generate reviewable Python, edit it as the source of truth, then re-export:
fabric-data-pipelines codegen path/to/Item.DataPipeline -o pipeline.py
Review the output (modeled types plus RawActivity for anything not modeled yet), edit in Python, call save_item, and sync via Git. Full walkthrough: Migrate from Fabric.
How this compares
| Tool | Role vs this library |
|---|---|
| Fabric UI + Git | Explore and debug in the portal; author typed, validated definitions here |
| fabricflow | Live REST API / templates / execute-monitor; this library is offline Git-first authoring |
| fabric-cicd | Deploy/promote items; this library authors the item folders it ships |
| Terraform Fabric provider | Infra and resource lifecycle; this library owns pipeline JSON/item content |
Longer write-up: How this compares.
Core concepts
Activities
Supported activity models include:
| Class | Fabric type |
Notes |
|---|---|---|
Copy |
Copy |
Typed SQL MI / Lakehouse / Warehouse sources and sinks |
Lookup |
Lookup |
|
Notebook |
TridentNotebook |
|
Dataflow |
RefreshDataFlow |
Dataflow Gen2 |
StoredProcedure |
SqlServerStoredProcedure |
|
Script |
Script |
Query / NonQuery blocks |
ExecutePipeline |
ExecutePipeline |
|
SetVariable / AppendVariable |
SetVariable / AppendVariable |
|
IfCondition |
IfCondition |
Nested activities |
ForEach |
ForEach |
Nested activities |
Switch |
Switch |
Cases + default |
Until |
Until |
Nested activities |
Wait |
Wait |
|
Fail |
Fail |
|
Web |
WebActivity |
HTTP via Fabric connection |
RawActivity |
(any) | Escape hatch for unmodeled types |
Not modeled yet (use RawActivity): GetMetadata, Azure Function, Teams/Outlook, and others. Track or request work via GitHub Issues.
Dependency chaining
lookup.then(copy).then(notebook) # Succeeded (default)
copy.then(notify, on="Failed") # Failed / Completed / Skipped
join.after(copy_a, copy_b) # fan-in
lookup >> copy # same as .then()
Expressions
from fabric_data_pipelines import expr
expr.parameter("run_date")
# '@pipeline().parameters.run_date'
expr.activity_output("get_tables", "value")
# "@activity('get_tables').output.value"
expr.library_variable("MyConnection")
expr.interp(expr.run_id()) # '@{pipeline().RunId}' for SQL interpolation
Schedules
Fabric stores schedules in a separate .schedules file alongside pipeline-content.json and .platform. Schedules must be attached on the pipeline via Pipeline(schedules=[...]) (multiple allowed, max 20) and are written by Pipeline.save_item().
from fabric_data_pipelines import Pipeline, Schedule, Wait, Weekly
schedule = Schedule(
enabled=True,
job_type="Execute",
configuration=Weekly(
start_date_time="2026-07-10T00:00:00",
end_date_time="2027-07-10T00:00:00",
local_time_zone_id="Romance Standard Time",
times=["21:30"],
weekdays=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
),
)
pipeline = Pipeline(
name="daily_load",
activities=[Wait(name="pause", wait_time_in_seconds=5)],
schedules=[schedule],
)
pipeline.save_item("out")
Validation
Activity models validate at construction (and on import): required fields, control-flow body rules, Copy sink/staging invariants, connector↔dataset pairing for known types, and similar per-activity checks. Finite choice rejections use InvalidChoiceError and list the allowed values (Pydantic surfaces these as ValidationError with that message). Unknown connector/dataset types and RawActivity remain escape hatches.
Pipeline.to_json() and Pipeline.save() call validate_graph() before serializing. That catches:
- duplicate activity names, including nested scopes
- unknown
dependsOntargets - cross-scope dependencies
- cycles in the dependency graph
Attaching more than 20 schedules on Pipeline(schedules=[...]) is rejected at construction time (Fabric limit).
Stable Fabric identity
When exporting Fabric item folders, logicalId handling matters:
- If you set
Pipeline(logical_id=...), thatlogicalIdstays stable across renames. - If you omit
logical_id, the library derives it deterministically fromPipeline.name. - If a
.platformfile already exists on disk, rewrites preserve its existinglogicalId.
If you rely on the derived value and later rename the pipeline, Fabric will treat it as a new item. Pin logical_id if identity continuity matters.
Documentation
fabric-data-pipelines.datalyft.io — guides, API reference, and pattern walkthroughs.
Feedback
Outside pull requests are closed for now. Prefer GitHub Issues — see CONTRIBUTING.md for what to include in bug reports and feature requests.
Development
uv sync
uv run ruff check
uv run ruff format --check
uv run mypy src tests
uv run pytest
Maintainer notes (releases, Amplify docs hosting): maintainers/.
License
MIT
Sponsors
This project is sponsored by datalyft.
Metadata
Release files for fabric-data-pipelines 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fabric_data_pipelines-0.3.0.tar.gz | 57.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fabric_data_pipelines-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 108.7 kB
Release files / fabric_data_pipelines-0.3.0.tar.gz
| Download URL | fabric_data_pipelines-0.3.0.tar.gz |
|---|---|
| Size | 57.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35c81dfd00f2c08f465e3e72cf8f616db6100a93767f41d2f54a872701f11774
|
|
BLAKE2b-256 checksum How to use checksums |
8438ea46c22e0204f70dbff706aac8a01a41d6781a7f87befc1302f6983b5128
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency logRelease files / fabric_data_pipelines-0.3.0-py3-none-any.whl
| Download URL | fabric_data_pipelines-0.3.0-py3-none-any.whl |
|---|---|
| Size | 50.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
411e38069f3c041f9def7b652c26bba5aed30403ae396f18a69c0b5a1b4e4c30
|
|
BLAKE2b-256 checksum How to use checksums |
61a2d054ac50ce7a9d61b6ce6d87628a4840a4480386c097a9ad3dbe8048d80a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency log