Integrate with Modal¶
Run Stardag tasks on Modal's serverless infrastructure.
Overview¶
Modal provides serverless cloud computing for engineers who want to build compute-intensive applications without managing infrastructure. The Stardag Modal integration enables:
- Serverless execution of tasks
- Automatic scaling
- Flexible routing of individual tasks to appropriate compute resources, including GPU access
Prerequisites¶
Modal Account¶
- Sign up for a Modal account.
- Optionally create a new dedicated Modal environment, or stick with the default
mainenvironment.
Stardag Registry Environment (Optional)¶
We recommend setting up the Stardag Registry.
You can also run Stardag on Modal, completely without the Registry.
Sign up at app.stardag.com or follow the setup guide for running it self-hosted.
You're all set. Just skip using a Stardag API-key in the examples.
Minimal Example from Scratch¶
We are going to create a new minimal Python project with the following structure:
Create and install the project¶
Create the new project (with uv as build system):
mkdir stardag-modal
cd stardag-modal
cat > pyproject.toml << 'EOF'
[project]
name = "stardag_modal"
version = "0.0.1"
requires-python = ">=3.12"
dependencies = ["stardag[modal]>=0.1.2", "modal"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
EOF
mkdir stardag_modal
touch stardag_modal/__init__.py
touch stardag_modal/main.py
And install it:
Now in stardag_modal/main.py let's define some minimal tasks that we can compose into a DAG:
# stardag_modal/main.py
import sys
import modal
import stardag as sd
import stardag.integration.modal as sd_modal
@sd.task(name="Range")
def get_range(limit: int) -> list[int]:
return list(range(limit))
@sd.task(name="Sum")
def get_sum(integers: sd.Depends[list[int]]) -> int:
return sum(integers)
Then let's define the modal image we will be using:
# stardag_modal/main.py continued...
# Must match local Python version for Modal serialization compatibility
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
# Define the Modal image
image = (
modal.Image.debian_slim(python_version=python_version)
.uv_sync()
.add_local_python_source("stardag_modal")
)
# Define the StardagApp
app = sd_modal.StardagApp(
"stardag-poc",
builder_settings=sd_modal.FunctionSettings(
image=image,
secrets=[
# required for communication with registry
modal.Secret.from_name("stardag-api-key"),
],
),
worker_settings={
"default": sd_modal.FunctionSettings(image=image),
},
)
# stardag_modal/main.py continued...
# Must match local Python version for Modal serialization compatibility
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
# Define the Modal image
image = (
modal.Image.debian_slim(python_version=python_version)
.uv_sync()
.add_local_python_source("stardag_modal")
)
# Define the StardagApp
app = sd_modal.StardagApp(
"stardag-poc",
builder_settings=sd_modal.FunctionSettings(image=image),
worker_settings={
"default": sd_modal.FunctionSettings(image=image),
},
)
And finally, compose the tasks and add a main section for building them on modal:
# stardag_modal/main.py continued...
root_task = get_sum(integers=get_range(limit=21))
if __name__ == "__main__":
res = app.build_spawn(root_task)
print(res)
Now that we have the code in place and the stardag and modal Python packages installed, we need to set up the environment before we can run the example.
Set up your Modal environment¶
Authenticate with modal (if you haven't already):
If you've created and want to use a dedicated Modal environment, make sure to also set:
Set up your Stardag environment¶
When running Stardag on Modal, we must use a remote filesystem for our target roots. A natural choice when running on Modal is to use Modal volumes:
Create a new isolated Stardag environment:
Add and activate a new profile for the environment:
We also need to give modal functions access to the Stardag Registry:
Deploy the app¶
Now let's deploy the app to Modal.
You should see output like:
Using active stardag profile
Registry URL: https://api.stardag.com
Workspace ID: <ws-id>
Environment ID: <env-id>
Target roots:
default: modalvol://stardag-poc/target-roots/default
Modal volumes:
default: stardag-poc
Functions:
build
worker_default
✓ Created objects.
├── 🔨 Created mount PythonPackage:stardag_modal
├── 🔨 Created mount PythonPackage:stardag
├── 🔨 Created function build.
└── 🔨 Created function worker_default.
✓ App deployed in 2.592s! 🎉
View Deployment: https://modal.com/apps/<modal-user>/<modal-env>/deployed/stardag-poc
You can also navigate to your modal apps in the relevant environment and should see:
Run the app¶
Now let's execute the main.py module:
Then navigate to the app in the Modal UI to follow the execution progress.
Inspect the results¶
The easiest way to get the results is to use an instance of the desired task and load its output.
Output:
You can also "tab" your way through the DAG dependencies to access root_task.integers:
If you connected to the Stardag Registry, you can also click the latest build to inspect the DAG execution.
See Also¶
- Stardag Modal Examples - Ready-to-run Modal examples in the
stardag-examplespackage. - Modal Documentation - Modal features
- ML Pipeline Example - Complete ML pipeline walkthrough
- Integrate with Prefect - Prefect orchestration