Blog
A Practical Guide to Dagster Resources

A Practical Guide to Dagster Resources

July 30, 2025
A Practical Guide to Dagster Resources
A Practical Guide to Dagster Resources

How dependency injection and smart resource management can save your sanity (and your deployments)

We talk a lot about how Dagster brings software engineering best practices to data engineering. Resources are an abstraction to help you not repeat yourself, handle dependency injection, testing, and building modular, scalable data platforms.

What Are Resources

Resources are a standard way of defining external services, tools, and storage locations in Dagster. Instead of hard-coding every database connection, API client, or storage location directly into your assets, you define them once as resources and inject them where needed.

Here's a simple example:

import dagster as dg

class DatabaseResource(dg.ConfigurableResource):
    connection_string: str
    
    def get_connection(self):
        # In real life, this would return a proper connection
        return f"Connected to {self.connection_string}"

@dg.asset
def user_data(database: DatabaseResource):
    conn = database.get_connection()
    # Your actual logic here
    return "user data"

If you can access it in Python, you can make a resource out of it. Databases, APIs, file systems, and legacy systems are all fair game.

Environment Management

Managing different environments is one of the challenging aspects of data engineering. This is mostly a function of cloud systems. Whether it is a data warehouse or distributed processing system, it can be difficult to replicate the same experience locally, in staging, and in production. To get around this with data warehouses, many data engineers use different databases and schemas for different environments, so you can have the same experience regardless of what environment you are in.

Here's how we handle this at Dagster:

import dagster as dg
import os

class SnowflakeResource(dg.ConfigurableResource):
    account: str
    user: str
    password: str
    database: str
    schema: str
    warehouse: str
    
    @property
    def connection_params(self):
        return {
            'account': self.account,
            'user': self.user,
            'password': self.password,
            'database': self.database,
            'schema': self._get_schema(),
            'warehouse': self.warehouse
        }
    
    def _get_schema(self):
        # Different schema based on environment
        env = os.getenv('DAGSTER_ENVIRONMENT', 'local')
        if env == 'prod':
            return self.schema
        elif env == 'staging':
            return f"{self.schema}_staging"
        else:
            return f"{self.schema}_{env}"

Now your assets don't need to know which environment they're running in—they just use the resource, and the resource figures out the rest:

@dg.asset
def daily_metrics(snowflake: SnowflakeResource):
    # This automatically goes to the right place
    query = "SELECT * FROM metrics WHERE date = CURRENT_DATE"
    # Execute against whatever environment we're in
    return execute_query(snowflake.connection_params, query)

Dependency Injection: Clean Architecture for Data Pipelines

Resources become really powerful when it comes to dependency injection. Instead of knowing about database connections, API keys, and file paths, your assets declare what they need. This separation keeps your business logic clean and focused on data transformation while handling infrastructure concerns separately.

Without resources, you might have something like this scattered across your codebase:

# Don't do this
@dg.asset
def messy_asset():
    # Hard-coded nightmare
    conn = snowflake.connector.connect(
        account='xy12345.us-east-1',
        user='data_eng_user',
        password='definitely_not_in_version_control',
        database='ANALYTICS_DB',
        schema='STAGING_SCHEMA',
        warehouse='COMPUTE_WH'
    )
    
    api_client = requests.Session()
    api_client.headers.update({
        'Authorization': 'Bearer another_secret_token',
        'User-Agent': 'our-data-pipeline/1.0'
    })
    
    # And then your actual business logic gets lost in the noise
    data = api_client.get('https://api.example.com/data')
    # ... do something with data
    return processed_data

With resources, your asset becomes clean and focused:

@dg.asset
def clean_asset(
    database: SnowflakeResource,
    api_client: APIResource
):
    # Clear, focused business logic
    raw_data = api_client.fetch_data()
    processed_data = transform_data(raw_data)
    database.save(processed_data)
    return processed_data

API Encapsulation 

One of our favorite uses for resources is wrapping REST APIs. Here's a real example from our Scout integration (which powers the ask-ai feature in our Slack channel and docs):

import dagster as dg
import requests
from typing import Dict, List

class ScoutResource(dg.ConfigurableResource):
    api_key: str
    base_url: str = "https://api.scout.example.com"
    
    def _get_headers(self) -> Dict[str, str]:
        return {
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json'
        }
    
    def write_documents(self, documents: List[Dict]) -> bool:
        """Upload documents to Scout for indexing"""
        response = requests.post(
            f"{self.base_url}/documents",
            json={"documents": documents},
            headers=self._get_headers()
        )
        return response.status_code == 200
    
    def search_documents(self, query: str) -> List[Dict]:
        """Search indexed documents"""
        response = requests.get(
            f"{self.base_url}/search",
            params={"q": query},
            headers=self._get_headers()
        )
        return response.json().get('results', [])

Now the assets that use Scout are nice and clean:

@dg.asset
def index_documentation(scout: ScoutResource):
    docs = load_documentation_from_somewhere()
    success = scout.write_documents(docs)
    return {"documents_indexed": len(docs), "success": success}

@dg.asset
def search_results(scout: ScoutResource):
    results = scout.search_documents("dagster best practices")
    return process_search_results(results)

Testing Without the Pain

Testing is one of those software engineering best practices that are often not practiced by less technical data practitioners. Introducing some simple functional tests can dramatically improve the reliability of your data platform. However, you want to be thoughtful in how you think about tests; nobody wants to spin up a Snowflake instance just to test that their transformation logic works. With resources, you can create lightweight mocks that return predictable test data:

class MockDatabaseResource(ConfigurableResource):
    def get_users(self):
        return [
            {"id": 1, "name": "Alice", "email": "alice@example.com"},
            {"id": 2, "name": "Bob", "email": "bob@example.com"}
        ]
    
    def save_processed_data(self, data):
        # In tests, just verify the data structure
        assert isinstance(data, list)
        assert all('processed_at' in item for item in data)
        return True

def test_user_processing():
    # Use the mock instead of real database
    result = user_processing_asset(MockDatabaseResource())
    assert len(result) == 2
    assert result[0]['processed_at'] is not None

Your tests run in milliseconds instead of minutes, and they're not dependent on external services. You're testing what actually matters: your business logic and data transformations.

We recently released a course around testing in Dagster on Dagster University and it is a great resource if you are new to testing in Data engineering or want to learn the best practices for Dagster. 

Configuration That Makes Sense

Resources surface their configuration in Dagster's UI under the deployment tab, making it easy to see which assets are using which resources and how they're configured. This visibility is crucial when you're debugging issues or onboarding new team members.

# In your definitions file
import dagster as dg

defs = dg.Definitions(
    assets=[user_data, daily_metrics, search_results],
    resources={
        "database": SnowflakeResource(
            account="xy12345.us-east-1",
            user="data_eng_user",
            password={"env": "SNOWFLAKE_PASSWORD"},
            database="ANALYTICS_DB",
            schema="PRODUCTION",
            warehouse="COMPUTE_WH"
        ),
        "scout": ScoutResource(
            api_key={"env": "SCOUT_API_KEY"}
        )
    }
)

When to Use Resources

Use resources whenever you need to interact with an API, database, or have a common pattern that you use throughout your project. If you're leveraging a Dagster integration like Fivetran or Snowflake, there's usually a resource you'll need to configure with your API keys and connection details.

The general rule: if you find yourself repeating the same setup code across multiple assets, that's a resource waiting to happen.

The Bigger Picture

Resources are one of those practices that make you a better engineer while solving practical problems. They enforce clean separation of concerns, make your code more testable, and save you from the environment-specific issues that come with hard-coded configurations.

More importantly, they scale with your team. When you have multiple people working on the same project, resources provide a standard way to interact with external services. New team members don't need to figure out how to connect to the database—they just use the resource.

Getting Started

Start small. Pick one external service you're currently hard-coding and turn it into a resource. You'll immediately see benefits in terms of code clarity and testability. Then expand from there.

Remember: if you can access it in Python, you can make a resource out of it. And trust us, your future self (and your teammates) will thank you for taking the time to do it right.

Have feedback or questions? Start a discussion in Slack or Github.

Interested in working with us? View our open roles.

Want more content like this? Follow us on LinkedIn.

Dagster Newsletter

Get updates delivered to your inbox

Latest writings

The latest news, technologies, and resources from our team.

Multi-Tenancy for Modern Data Platforms
Webinar

April 7, 2026

Multi-Tenancy for Modern Data Platforms

Learn the patterns, trade-offs, and production-tested strategies for building multi-tenant data platforms with Dagster.

Deep Dive: Building a Cross-Workspace Control Plane for Databricks
Webinar

March 24, 2026

Deep Dive: Building a Cross-Workspace Control Plane for Databricks

Learn how to build a cross-workspace control plane for Databricks using Dagster — connecting multiple workspaces, dbt, and Fivetran into a single observable asset graph with zero code changes to get started.

Dagster Running Dagster: How We Use Compass for AI Analytics
Webinar

February 17, 2026

Dagster Running Dagster: How We Use Compass for AI Analytics

In this Deep Dive, we're joined by Dagster Analytics Lead Anil Maharjan, who demonstrates how our internal team utilizes Compass to drive AI-driven analysis throughout the company.

Making Dagster Easier to Contribute to in an AI-Driven World
Making Dagster Easier to Contribute to in an AI-Driven World
Blog

April 1, 2026

Making Dagster Easier to Contribute to in an AI-Driven World

AI has made contributing to open source easier but reviewing contributions is still hard. At Dagster, we’re improving the contributor experience with smarter review tooling, clearer guidelines, and a focus on contributions that are easier to evaluate, merge, and maintain.

DataOps with Dagster: A Practical Guide to Building a Reliable Data Platform
DataOps with Dagster: A Practical Guide to Building a Reliable Data Platform
Blog

March 17, 2026

DataOps with Dagster: A Practical Guide to Building a Reliable Data Platform

DataOps is about building a system that provides visibility into what's happening and control over how it behaves

Unlocking the Full Value of Your Databricks
Unlocking the Full Value of Your Databricks
Blog

March 12, 2026

Unlocking the Full Value of Your Databricks

Standardizing on Databricks is a smart strategic move, but consolidation alone does not create a working operating model across teams, tools, and downstream systems. By pairing Databricks and Unity Catalog with Dagster, enterprises can add the coordination layer needed for dependency visibility, end-to-end lineage, and faster, more confident delivery at scale.

How Magenta Telekom Built the Unsinkable Data Platform
Case study

February 25, 2026

How Magenta Telekom Built the Unsinkable Data Platform

Magenta Telekom rebuilt its data infrastructure from the ground up with Dagster, cutting developer onboarding from months to a single day and eliminating the shadow IT and manual workflows that had long slowed the business down.

Scaling FinTech: How smava achieved zero downtime with Dagster
Case study

November 25, 2025

Scaling FinTech: How smava achieved zero downtime with Dagster

smava achieved zero downtime and automated the generation of over 1,000 dbt models by migrating to Dagster's, eliminating maintenance overhead and reducing developer onboarding from weeks to 15 minutes.

Zero Incidents, Maximum Velocity: How HIVED achieved 99.9% pipeline reliability with Dagster
Case study

November 18, 2025

Zero Incidents, Maximum Velocity: How HIVED achieved 99.9% pipeline reliability with Dagster

UK logistics company HIVED achieved 99.9% pipeline reliability with zero data incidents over three years by replacing cron-based workflows with Dagster's unified orchestration platform.

Modernize Your Data Platform for the Age of AI
Guide

January 15, 2026

Modernize Your Data Platform for the Age of AI

While 75% of enterprises experiment with AI, traditional data platforms are becoming the biggest bottleneck. Learn how to build a unified control plane that enables AI-driven development, reduces pipeline failures, and cuts complexity.

Download the eBook on how to scale data teams
Guide

November 5, 2025

Download the eBook on how to scale data teams

From a solo data practitioner to an enterprise-wide platform, learn how to build systems that scale with clarity, reliability, and confidence.

Download the e-book primer on how to build data platforms
Guide

February 21, 2025

Download the e-book primer on how to build data platforms

Learn the fundamental concepts to build a data platform in your organization; covering common design patterns for data ingestion and transformation, data modeling strategies, and data quality tips.