Multi-script apps
Real-world applications often span multiple files. This page shows how to build FastAPI and Streamlit apps with multiple Python files.
FastAPI multi-script app
Project structure
project/
├── app.py # Main FastAPI app file
└── module.py # Helper moduleExample: Multi-file FastAPI app
"""Multi-file FastAPI app example."""
from fastapi import FastAPI
from module import function # Import from another file
import pathlib
import flyte
from flyte.app.extras import FastAPIAppEnvironment
app = FastAPI(title="Multi-file FastAPI Demo")
app_env = FastAPIAppEnvironment(
name="fastapi-multi-file",
app=app,
image=flyte.Image.from_debian_base(python_version=(3, 12)).with_pip_packages(
"fastapi",
"uvicorn",
),
resources=flyte.Resources(cpu=1, memory="512Mi"),
requires_auth=False,
# FastAPIAppEnvironment automatically includes necessary files
# But you can also specify explicitly:
# include=["app.py", "module.py"],
)
@app.get("/")
async def root():
return function() # Uses function from module.py
if __name__ == "__main__":
flyte.init_from_config(root_dir=pathlib.Path(__file__).parent)
app_deployment = flyte.deploy(app_env)
print(f"Deployed: {app_deployment[0].url}")
def function():
"""Helper function used by the FastAPI app."""
return {"message": "Hello from module.py!"}
Automatic file discovery
FastAPIAppEnvironment automatically discovers and includes the necessary files by analyzing your imports. However, if you have files that aren’t automatically detected (like configuration files or data files), you can explicitly include them:
app_env = FastAPIAppEnvironment(
name="fastapi-with-config",
app=app,
include=["app.py", "module.py", "config.yaml"], # Explicit includes
# ...
)Streamlit multi-script app
Project structure
project/
├── main.py # Main Streamlit app
├── utils.py # Utility functions
└── components.py # Reusable componentsExample: Multi-file Streamlit app
# main.py
import streamlit as st
from utils import process_data
from components import render_chart
st.title("Multi-file Streamlit App")
data = st.file_uploader("Upload data file")
if data:
processed = process_data(data)
render_chart(processed)# utils.py
import pandas as pd
def process_data(data_file):
"""Process uploaded data file."""
df = pd.read_csv(data_file)
# ... processing logic ...
return df# components.py
import streamlit as st
def render_chart(data):
"""Render a chart component."""
st.line_chart(data)Deploying multi-file Streamlit app
import flyte
import flyte.app
image = flyte.Image.from_debian_base(python_version=(3, 12)).with_pip_packages(
"streamlit==1.41.1",
"pandas==2.2.3",
)
app_env = flyte.app.AppEnvironment(
name="streamlit-multi-file",
image=image,
args="streamlit run main.py --server.port 8080",
port=8080,
include=["main.py", "utils.py", "components.py"], # Include all files
resources=flyte.Resources(cpu="1", memory="1Gi"),
requires_auth=False,
)
if __name__ == "__main__":
flyte.init_from_config()
app = flyte.deploy(app_env)
print(f"App URL: {app[0].url}")Complex multi-file example
Here’s a more complex example with multiple modules:
Project structure
project/
├── app.py
├── models/
│ ├── __init__.py
│ └── user.py
├── services/
│ ├── __init__.py
│ └── auth.py
└── utils/
├── __init__.py
└── helpers.pyExample code
# app.py
from fastapi import FastAPI
from models.user import User
from services.auth import authenticate
from utils.helpers import format_response
app = FastAPI(title="Complex Multi-file App")
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = User(id=user_id, name="John Doe")
return format_response(user)# models/user.py
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str# services/auth.py
def authenticate(token: str) -> bool:
# ... authentication logic ...
return True# utils/helpers.py
def format_response(data):
return {"data": data, "status": "success"}Deploying complex app
from flyte.app.extras import FastAPIAppEnvironment
import flyte
app_env = FastAPIAppEnvironment(
name="complex-app",
app=app,
image=flyte.Image.from_debian_base(python_version=(3, 12)).with_pip_packages(
"fastapi",
"uvicorn",
"pydantic",
),
# Include all necessary files
include=[
"app.py",
"models/",
"services/",
"utils/",
],
resources=flyte.Resources(cpu=1, memory="512Mi"),
)Best practices
- Use explicit includes: For Streamlit apps, explicitly list all files in
include - Automatic discovery: For FastAPI apps,
FastAPIAppEnvironmenthandles most cases automatically - Organize modules: Use proper Python package structure with
__init__.pyfiles - Test locally: Test your multi-file app locally before deploying
- Include all dependencies: Include all files that your app imports
Troubleshooting
Import errors:
- Verify all files are included in the
includeparameter - Check that file paths are correct (relative to app definition file)
- Ensure
__init__.pyfiles are included for packages
Module not found:
- Add missing files to the
includelist - Check that import paths match the file structure
- Verify that the image includes all necessary packages
File not found at runtime:
- Ensure all referenced files are included
- Check mount paths for file/directory inputs
- Verify file paths are relative to the app root directory