What Is Dagster? β Definition and How It Works
Learn what Dagster is, how asset-oriented orchestration differs from task-oriented, and where it fits a collection pipeline.
Dagster is a data orchestrator organised around assets β the datasets a pipeline produces β rather than around tasks. You declare what should exist and how to compute it, and Dagster works out the order.
1. Assets Instead of Tasks
A task-oriented orchestrator asks: what runs, in what order?
Dagster asks: what data should exist, and what does each piece depend on?
from dagster import asset
@asset
def raw_listings(context):
rows = fetch_listings()
context.add_output_metadata({"rows": len(rows)})
return rows
@asset
def clean_listings(raw_listings):
return [normalize(r) for r in raw_listings if is_valid(r)]
@asset
def listing_report(clean_listings):
return build_report(clean_listings)
Dependencies come from the function parameters. The graph is derived, not declared separately β so it cannot drift out of sync with the code.
2. Why That Difference Matters
| Question | Task-oriented | Asset-oriented |
|---|---|---|
| What does this dataset depend on? | Read the DAG definition | Built in |
| Is this data current? | Check when the task last ran | Ask the asset |
| Rebuild only what changed | Manual task selection | Native |
| What broke downstream? | Trace by hand | Lineage is explicit |
| Which data did this run produce? | Inferred | Recorded |
For a collection pipeline the practical gain is targeted rebuilds. When a parser is fixed, the asset that depends on the parser and everything downstream needs rematerialising β while the raw fetch, which is the expensive and rate-limited part, does not.
3. Partitions
Time-partitioned assets model daily collection directly:
from dagster import asset, DailyPartitionsDefinition
daily = DailyPartitionsDefinition(start_date="2026-01-01")
@asset(partitions_def=daily)
def daily_serp(context):
day = context.partition_key
return collect_serp(day)
Each day is a separate materialisation with its own status, so a backfill is a range of partitions and a failed day is one partition to retry β not a whole pipeline to re-run.
4. Resources and Testability
External dependencies are injected as resources rather than constructed inside asset code:
from dagster import ConfigurableResource
class ScraperClient(ConfigurableResource):
api_key: str
def fetch(self, url): ...
@asset
def raw_pages(scraper: ScraperClient):
return [scraper.fetch(u) for u in seed_urls()]
Two consequences. Credentials come from configuration rather than being embedded in code, and a test substitutes a fake resource β so asset logic is unit-testable without network access, which is unusual among orchestrators.
5. Freshness and Sensors
Freshness policies declare how current an asset should be, turning staleness into an observable condition instead of something noticed when a report looks wrong.
Sensors trigger materialisation on external events β a file arriving, a queue message, an upstream update β which suits event-driven collection better than a fixed schedule.
6. Where It Fits Collection Work
The natural mapping:
raw_pages (partitioned by day, expensive, rate-limited)
β parsed_records (cheap, changes when the parser changes)
β deduplicated
β published_table
β report
Because the raw layer is a separate asset, re-parsing never re-fetches. That single property is worth more than any scheduling feature when the source cannot be re-read and requests are limited.
7. Compared With Other Orchestrators
| Tool | Model | Notes |
|---|---|---|
| Dagster | Asset-oriented | Lineage, partitions, strong local testing |
| Airflow | Task-oriented | Largest ecosystem, most operators |
| Prefect | Flow-oriented | Lightest to adopt, dynamic workflows |
| Cron plus scripts | None | Fine until it is not |
Airflow's ecosystem is larger; Dagster's model is a better fit where the pipeline's purpose is producing datasets, which is exactly the case for collection.
8. Summary
Dagster orchestrates around assets β the datasets produced β deriving the dependency graph from code, tracking lineage and materialisation, and supporting partitions, freshness policies, and injectable resources.
For collection pipelines its decisive advantage is separating expensive fetches from cheap transformations, so fixing a parser rematerialises the derived assets without re-requesting anything from the source.