Skip to main content

Example app

FastAPI apps can be structured in many ways. For demonstration purposes, this example provides a simple, deployable FastAPI app on Sevalla. The concepts shown here can be applied to any FastAPI application. What’s included in the example app:

Database models

This app uses SQLModel as its ORM. All database models should inherit from the SQLModel class, which is imported in models.py. This ensures consistency and smooth integration with the app’s database layer.
# app/models.py
from sqlmodel import SQLModel
SQLModel needs a connection to your database, which requires creating an engine. The database URL is provided via the SQLALCHEMY_DATABASE_URI setting, which will be defined in config.py later.
# app/core/db.py
from sqlmodel import create_engine

from app.core.config import settings

engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI))
You need to create a session and a session dependency so your routes can create, read, and modify SQLModel objects.
# app/api/deps.py
from fastapi import Depends
from sqlmodel import Session
from typing import Annotated

from app.core.db import engine

def get_session():
    with Session(engine) as session:
        yield session


SessionDep = Annotated[Session, Depends(get_session)]
Alembic is used for database migrations. The alembic directory and its files were generated by the alembic init app/alembic command. Inside that directory, the app/alembic/env.py and app/alembic/script.py.mako files need to be updated to work with your app. For alembic.env.py, the SQLModel class needs to be imported from models.py, and the database URL needs to be referenced when migrations are run.
# app/alembic.env.py
...

target_metadata = None
from app.models import SQLModel 
from app.core.config import settings
target_metadata = SQLModel.metadata

...

def get_url(): 
    return str(settings.SQLALCHEMY_DATABASE_URI)

...

def run_migrations_offline() -> None:
    url = config.get_main_option("sqlalchemy.url") 
    url = get_url() 

...

def run_migrations_online() -> None:
    configuration = config.get_section(config.config_ini_section) 
    configuration["sqlalchemy.url"] = get_url() 
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}), 
        configuration, 
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )
Update app/alembic/script.py.mako to include an import for sqlmodel.
# app/alembic/script.py.mako
from alembic import op
import sqlalchemy as sa
import sqlmodel 

App settings

The pydantic-settings package manages all configuration values for the app. If a .env file is present, its values will be loaded automatically. Otherwise, the app will fall back to the environment variables defined on the system. The only required setting for this example is SQLALCHEMY_DATABASE_URI, which specifies the connection string used to connect to your database.
# app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env")

    SQLALCHEMY_DATABASE_URI: str = ""

settings = Settings()
In a development environment, you can create a .env file to store configuration values that will be loaded when the app starts. When deploying to Sevalla, these environment variables can be configured directly through Sevalla instead.
# .env
SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://<user>:<password>@<hostname>:<port>/<db_name>

Main file

The app’s entry point is main.py, where you need to instantiate the FastAPI app object.
# app/main.py
from fastapi import FastAPI
from app.core.config import settings

app = FastAPI()

Requirements

The following installs all the requirements for this example app:
pip install fastapi[all] sqlmodel
pip install alembic psycopg2-binary
pip freeze > requirements.txt

Add a hosted database

The filesystem used for your app will be recreated on each deploy, so an SQLite database isn’t suitable for production. Instead, you can use a hosted database on Sevalla for your app. Create a database in Sevalla and select either Postgres, MySQL, or MariaDB. You also need to install a database driver if you haven’t already done so. For example, with Postgres, you can use psycopg2-binary.
pip install psycopg2-binary

Nixpacks

By default, Sevalla uses Nixpacks to build your application. After you add the application, you need to add custom commands that will both start your app and run migrations before every deploy. To update the start command, go to Processes > Web process > Update process and add fastapi run app/main.py as your custom start command. For migrations, you can create a job to run the migrate command before the container is started. To do this, after you add your application, go to Processes > Create job > Job. For the start command, add alembic upgrade head. The start policy should be before deployment, and the smallest instance size should be sufficient for migrations.

Dockerfile

To build your application using a Dockerfile, ensure it ends with your FastAPI app being started by the app server. Below is a sample Dockerfile that sets up a Python environment, installs dependencies, and launches the server.
FROM python:latest  

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1 
 
RUN mkdir /app
WORKDIR /app
 
RUN pip install --upgrade pip 
COPY requirements.txt  .
RUN pip install --no-cache-dir -r requirements.txt
 
COPY . .
 
CMD ["fastapi", "run", "app/main.py"]
The command to start FastAPI must reference the name of the file containing your FastAPI app object. The rest of the Dockerfile can be customized according to your project’s specific needs.

Migrations

For migrations, you can create a job to run the migrate command before the container is started. To do this, after you add your application, go to Processes > Create job > Job. For the start command, add alembic upgrade head. The start policy should be before deployment, and the smallest instance size should be sufficient for migrations.

Build settings

By default, Sevalla builds applications using Nixpacks, so the build strategy must be updated before your Dockerfile can be used. To update the build strategy, after you add your application, go to Settings > Update build strategy and change the build strategy from Nixpacks to Dockerfile.

Deploy on Sevalla

To deploy your app to Sevalla using Git, your code must be hosted in a Git repository. Sevalla supports any public Git repository or private repositories from GitHub, Bitbucket, and GitLab. You’ll need to connect your repo host account with Sevalla if you are using a private repo. Your repo should have a .gitignore that ignores SQLite files, .env files, virtual environments, __pycache__/, any other files that either have sensitive information or don’t need to be tracked in git. Here is an example .gitignore file:
__pycache__/ 
.env
.venv/
env/
venv/
*.sqlite3
You can now add your application in Sevalla and choose the branch and repository for your project. Ensure that you set the location for your application to match the location of your database, allowing them to communicate over an internal network. If your app requires more resources than the defaults of 0.3 GB RAM and 0.3 CPU, then switch to a larger instance size. After adding your application, you can configure the environment variables it requires. For this example, only SQLALCHEMY_DATABASE_URI is needed. Since this variable holds your database URL, go to Networking and click Add internal connection. Select the database you created earlier, and then select Add environment variables to the application. Rename DB_URL to SQLALCHEMY_DATABASE_URI and click Add internal connection.
If you are using PostgreSQL, make sure the connection string starts with postgresql:// (not postgres://) so SQLModel can connect properly.