Dagster: Data Orchestration with Assets, Jobs & Sensors
Dagster is the cloud-native data orchestration platform that treats data assets — not tasks — as first-class citizens. Get full data lineage, asset materialization tracking, and a rich observability UI out of the box.
What is Dagster?
Dagster is an open-source data orchestration platform designed around the concept of Software-Defined Assets (SDAs) — Python functions that declare what data artifacts they produce and depend on. Unlike Airflow which orchestrates tasks, Dagster orchestrates data: it tracks the materialization state of every asset, shows the full lineage graph from raw sources to final models, and surfaces data freshness and quality at the platform level.
Dagster integrates natively with dbt (model assets), Airbyte (source assets), Spark, Snowflake, BigQuery, and most of the modern data stack. The Dagit web UI provides an interactive asset graph, run history with per-step logs, a partition viewer for backfill monitoring, and a sensor dashboard. Dagster Cloud is the managed offering; Dagster Open Source can be self-hosted with dagster dev for local development.
Software-Defined Assets
# pip install dagster dagster-webserver
from dagster import asset, AssetExecutionContext, Definitions
import pandas as pd
# Software-Defined Assets — define the data, not the task
@asset(
group_name="raw",
description="Raw orders from the API",
)
def raw_orders(context: AssetExecutionContext) -> pd.DataFrame:
import httpx
data = httpx.get("https://api.example.com/orders").json()
df = pd.DataFrame(data)
context.log.info(f"Fetched {len(df)} orders")
return df
@asset(
group_name="staging",
deps=[raw_orders],
description="Cleaned orders with USD amounts",
)
def stg_orders(raw_orders: pd.DataFrame) -> pd.DataFrame:
df = raw_orders.copy()
df["amount_usd"] = df["amount_cents"] / 100
df = df[df["status"] != "cancelled"]
df["created_at"] = pd.to_datetime(df["created_at"])
return df
@asset(
group_name="marts",
deps=[stg_orders],
description="Revenue aggregated by region and month",
)
def revenue_by_region(stg_orders: pd.DataFrame) -> pd.DataFrame:
return (
stg_orders
.assign(month=lambda df: df["created_at"].dt.to_period("M"))
.groupby(["region", "month"])
.agg(revenue=("amount_usd", "sum"), orders=("order_id", "count"))
.reset_index()
)
# Definitions — registers all assets, jobs, schedules, resources
defs = Definitions(assets=[raw_orders, stg_orders, revenue_by_region]) Jobs, Schedules, Sensors & Resources
# Jobs, Schedules, Sensors & Resources
from dagster import (
define_asset_job, ScheduleDefinition, sensor,
RunRequest, SensorEvaluationContext, resource,
Definitions, EnvVar,
)
from dagster_postgres import PostgresIOManager
# Job — subset of assets to materialize together
etl_job = define_asset_job(
name="nightly_etl",
selection=["raw_orders", "stg_orders", "revenue_by_region"],
)
# Schedule — run the job on a cron
nightly_schedule = ScheduleDefinition(
job=etl_job,
cron_schedule="0 2 * * *", # 2am UTC daily
execution_timezone="UTC",
)
# Sensor — trigger a run when a new S3 file appears
@sensor(job=etl_job, minimum_interval_seconds=60)
def new_file_sensor(context: SensorEvaluationContext):
import boto3
s3 = boto3.client("s3")
paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket="my-bucket", Prefix="inbox/"):
for obj in page.get("Contents", []):
key = obj["Key"]
if key not in context.cursor:
yield RunRequest(
run_key=key,
run_config={"ops": {"raw_orders": {"config": {"s3_key": key}}}},
)
# Resource — shared database connection
postgres_resource = PostgresIOManager(
host=EnvVar("POSTGRES_HOST"),
database=EnvVar("POSTGRES_DB"),
)
defs = Definitions(
assets=[raw_orders, stg_orders, revenue_by_region],
jobs=[etl_job],
schedules=[nightly_schedule],
sensors=[new_file_sensor],
resources={"io_manager": postgres_resource},
) Partitioned Assets & Backfills
# Partitioned assets — process data day by day
from dagster import (
asset, DailyPartitionsDefinition, AssetExecutionContext,
build_asset_context, materialize,
)
daily_partitions = DailyPartitionsDefinition(start_date="2024-01-01")
@asset(
partitions_def=daily_partitions,
group_name="raw",
)
def daily_events(context: AssetExecutionContext) -> pd.DataFrame:
date = context.partition_key # "2024-01-15"
url = f"https://api.example.com/events?date={date}"
return pd.DataFrame(httpx.get(url).json())
@asset(
partitions_def=daily_partitions,
deps=[daily_events],
)
def daily_summary(daily_events: pd.DataFrame) -> dict:
return {
"total_events": len(daily_events),
"unique_users": daily_events["user_id"].nunique(),
}
# Backfill a date range from CLI:
# dagster asset backfill --select daily_events daily_summary \
# --partition-range 2024-01-01...2024-01-31 Dagster vs Airflow vs Prefect
| Feature | Dagster | Apache Airflow | Prefect |
|---|---|---|---|
| Paradigm | Asset-based | Task DAG | Flow/Task |
| Data lineage | First-class (asset graph) | Plugin required | Limited |
| UI | Dagit (self-hosted) | Webserver (self-hosted) | Prefect Cloud / self-hosted |
| dbt integration | Native (dbt assets) | BashOperator / dbt-airflow | prefect-dbt |
| Learning curve | Medium–High | Medium | Low |
| Best for | Data platform / lineage | Complex ETL, large teams | Python-native quick start |
Frequently Asked Questions
What is the difference between asset-based and task-based orchestration?▼
Task-based orchestration (Airflow, Prefect) thinks in terms of actions — run this task, then that task. You define the execution sequence and the tasks produce side effects (writing to a database). Asset-based orchestration (Dagster) thinks in terms of data artifacts — define the assets you want to exist and how to produce them. Dagster tracks which assets are materialized, shows lineage between assets, and can automatically determine which assets need to be re-run when upstream data changes. This shift makes it easier to answer 'what data do we have and how was it produced?'
What are Software-Defined Assets in Dagster?▼
Software-Defined Assets (SDAs) are Python functions decorated with @asset that declare what data artifact they produce and what upstream data they depend on. Unlike Airflow tasks which are operations, assets are descriptions of data. Dagster tracks the materialization status of each asset — when it was last materialized, with what code version, and whether it is stale relative to its upstream dependencies. The Dagit UI shows a live asset graph with materialization history, making it easy to see the state of your entire data platform at a glance.
What is the Dagit UI and what can I do with it?▼
Dagit is Dagster's web interface (dagster-webserver package). It provides: an Asset Catalog showing all defined assets with their lineage graph and materialization status, a Launchpad for running jobs with custom configuration, a Runs view with per-step logs and timing, a Schedules and Sensors tab for monitoring trigger status, and a Partitions tab for viewing backfill progress. Run dagster dev to start both the webserver and daemon locally. Dagit is the primary observability surface for a Dagster deployment.
How do Dagster Resources work?▼
Resources are reusable, configurable objects that provide shared infrastructure to assets and ops — database connections, API clients, cloud storage handles. Define a resource using the @resource decorator or by subclassing ConfigurableResource. Resources are injected into assets as function parameters by name. In the Definitions object, map resource keys to implementations. This allows you to swap implementations between environments: in development, inject a local SQLite resource; in production, inject a PostgreSQL resource. Resources eliminate the need to create clients inside each function.
When should I choose Dagster over Airflow?▼
Choose Dagster when data lineage and asset observability are important — knowing what data exists, when it was produced, and whether it is stale. Dagster's asset graph is a first-class concept, not a bolt-on. Choose Dagster when your team thinks in terms of data products rather than scheduled scripts. Choose Airflow when you have existing Airflow DAGs and a large team familiar with it, need specific Airflow operators not available in Dagster's integrations, or work in a data engineering context where Airflow is the established standard. Dagster has a higher learning curve than Prefect but more powerful data modeling concepts.
What is the difference between @op, @job, and @asset in Dagster?▼
@op is the lowest-level unit of computation — a function that takes inputs and returns outputs, similar to a Prefect task. @job is a graph of @ops that can be scheduled and run. @asset is a higher-level abstraction — an @op that produces a named data artifact tracked in the asset catalog. For new Dagster projects, prefer @asset over @op/@job — the SDA paradigm provides better observability and is the recommended approach. @op and @job are useful for computational pipelines that do not produce reusable data artifacts, or for migrating from Airflow with a task-centric mental model.
Related Products
on GumroadDeveloper Productivity Bundle
Stop rebuilding the same setup every project. 51 VSCode snippets, 40 Git aliases, 5 Docker Compose stacks, 5 GitHub Actions workflows, 5 README templates, and a dotfiles kit. Set up a professional dev environment in under an hour.
Buy on Gumroad →AI Prompt Engineering Toolkit
58 structured prompt templates for Claude, ChatGPT, and Gemini — organized by use case. Code Review, Debugging, Documentation, Architecture, and 10 model-specific tips. Stop writing prompts from scratch.
Buy on Gumroad →Developer Cheat Sheet Bundle
10 print-ready cheat sheets for the tools developers use every day: Git, Docker, Linux CLI, SQL, Regex, HTTP Status codes, VS Code shortcuts, Bash scripting, jq/JSON, and Markdown.
Buy on Gumroad →You Might Also Need
JSON Formatter & Validator
Format, beautify, and validate JSON online. Paste your JSON to instantly pretty-print it with 2-space, 4-space, or tab indentation. Minify JSON too. Free, runs in your browser.
Open free tool →
Regex Tester
Free regex tester. Test regular expressions against multiple strings with expected match/no-match assertions — see instant pass/fail results. Built-in presets for email, URL, IPv4, and phone. Pro: unl
Open free tool →
Base64 Encoder & Decoder
Free Base64 Encoder & Decoder. Convert text, images, and any file to Base64 and back. Supports URL-safe Base64, image data URIs, and file download from Base64. Runs 100% in your browser — no data sent
Open free tool →
More Free Tools
Related Articles
Apache Airflow vs Prefect: Workflow Orchestration Comparison 2026
Apache Airflow vs Prefect 2026: DAG vs flow syntax, scheduling, dynamic workflows, observability, learning curve, cloud offerings, and which to choose for your data team.
Apache Kafka for Real-Time Data Pipelines: Tutorial 2026
Apache Kafka tutorial 2026: topics, partitions, consumer groups, producers/consumers in Python, Schema Registry, Kafka Connect, exactly-once semantics, and production best practices.
Apache Spark vs Flink: Stream Processing Comparison 2026
Apache Spark vs Apache Flink 2026: architecture differences, true streaming vs micro-batch, latency, exactly-once semantics, SQL support, state management, and when to choose each.
DuckDB vs PostgreSQL for Analytics: When to Choose Each 2026
DuckDB vs PostgreSQL 2026: OLAP vs OLTP, query performance on large datasets, Parquet/CSV support, and when to choose DuckDB for analytics workloads.
ETL vs ELT: Modern Data Pipeline Architecture Guide 2026
ETL vs ELT data pipeline comparison 2026: traditional ETL limitations, cloud ELT advantages, dbt for transformation, tools comparison (Fivetran/Airbyte/dbt), and when to use each approach.
Enjoying this tool? Get more like it.
Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.
Unlock AI-Powered Dev Tools
- ⚡ AI Code Review, Doc Generator & SQL Builder
- ⚡ All premium templates & early access
- ⚡ Member discounts on Gumroad products
$9/mo after trial · Cancel anytime
Want the full toolkit?
Get DevPlaybook Pro
Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.
MIT licensed · Instant download · No subscription
See what's included → Browse all deals →