Dagster data orchestration best practices — project structure, assets, resources, testing, and common pitfalls
Start with a single definitions.py. Split when files exceed ~400 lines:
src/my_project/
├── __init__.py
├── definitions.py # Definitions object — single entry point
├── assets.py # @asset functions
├── resources.py # ConfigurableResource classes
├── schedules.py
├── sensors.py
└── defs/ # Subdirectories by domain or technology
├── ingestion/
└── reporting/
Use load_assets_from_package_module() to auto-discover assets from subdirectories.
from dagster import asset, AssetIn, AssetCheckResult, asset_check
@asset(group_name="ingestion", key_prefix="raw")
def raw_orders(db: DatabaseResource) -> pd.DataFrame:
return db.query("SELECT * FROM orders")
@asset(ins={"raw_orders": AssetIn(key_prefix="raw")})
def cleaned_orders(raw_orders: pd.DataFrame) -> pd.DataFrame:
return raw_orders.dropna(subset=["order_id"])
@asset_check(asset=cleaned_orders)
def no_null_ids(cleaned_orders: pd.DataFrame) -> AssetCheckResult:
passed = cleaned_orders["order_id"].notna().all()
return AssetCheckResult(passed=passed)
group_name and key_prefix for organization.asset_check for data quality validation.from dagster import ConfigurableResource
class DatabaseResource(ConfigurableResource):
connection_string: str
def query(self, sql: str) -> pd.DataFrame:
...
ConfigurableResource for all external connections.Definitions object.build_sensor_context and validate_run_config.build_schedule_context.def test_cleaned_orders():
raw = pd.DataFrame({"order_id": [1, None, 3], "amount": [10, 20, 30]})
result = cleaned_orders(raw)
assert result["order_id"].notna().all()
assert len(result) == 2
build_asset_context() when assets need context.validate_run_config.| Avoid | Do Instead |
|---|---|
| Hardcoded connection strings in assets | Use ConfigurableResource |
| Business logic inside @asset functions | Extract to utility modules, keep assets as orchestration glue |
| materialize_to_memory in production | Use Definitions with proper resources |
| Monolithic definitions.py beyond 400 lines | Split by domain or technology |
| Ignoring asset checks | Add checks for key data quality invariants |
Load this skill when building or modifying Dagster pipelines, assets, resources, sensors, or schedules.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer