File and project structure

Apps spanning multiple files

If you have a project spanning multiple files, you can either use a single Modal App to create Modal resources across all of them or compose multiple apps using app.include(other_app) into a single app at deploy time.

In this guide we’ll show you how to use composition of multiple smaller files with their own “apps” in order to cleanly separate different parts of your app into multiple files. You can see a realistic instance of a single app use in our LLM + TTS example.

Assume we have a package named pkg with files a.py and b.py that contain functions we want to deploy:

pkg/
├── __init__.py
├── a.py
└── b.py
# pkg/a.py
a_app = modal.App("a")  # Note: prior to April 2024, "app" was called "stub"
image_1 = modal.Image.debian_slim().pip_install("some_package")

@a_app.function(image=image_1)
def f():
    ...
# pkg/b.py
b_app = modal.App("b")  # Note: prior to April 2024, "app" was called "stub"
image_2 = modal.Image.debian_slim().pip_install("other_package")

@b_app.function(image=image_2)
def g():
    ...

To deploy these resources together, make a single deployment file, perhaps deploy.py (the name itself doesn’t matter), that imports the apps from each of the sub-modules and includes them in a common parent app that represents your entire app:

# pkg/deploy.py
from .a import a_app
from .b import b_app

app = modal.App("multi-file-app")  # Note: prior to April 2024, "app" was called "stub"
app.include(a_app)
app.include(b_app)

Now you can deploy your app by running modal deploy pkg.deploy from above the pkg directory. Your deployed Modal app will have both the f and g functions.

The final file structure now looks like this:

pkg/
├── __init__.py
├── a.py
├── b.py
└── deploy.py

One advantage of splitting up apps this way is that you can opt to run only part of your larger app during development. For example, running modal run a.py to test some functionality in that part without having to process any changes to the rest of the app.

Tip: you can also make __init__.py your deployment file, which makes deploying a package slightly more convenient. With this, you can deploy your entire project using just modal deploy pkg.

Note: Since the multi-file app still has a single namespace for all functions, it’s important to name your Modal functions uniquely across the project even when splitting it up across files - otherwise you risk some functions “shadowing” others with the same name.