DEV Community

Cover image for A Practical Project Structure for FastAPI Applications
Sreeraj Sreenivasan
Sreeraj Sreenivasan

Posted on

A Practical Project Structure for FastAPI Applications

A short guide to organizing FastAPI apps beyond a single main.py file.

FastAPI makes it easy to start with a single main.py file. That is great for demos, prototypes, and small APIs.

But once your application grows, one file can quickly turn into a mix of routes, database logic, security helpers, settings, and business rules. A clear project structure helps keep the app easier to understand, test, and extend.

Here is a practical FastAPI structure for growing backend applications:

.
├── app/
│   ├── api/
│   │   └── v1/
│   │       ├── endpoints/
│   │       └── router.py
│   ├── core/
│   ├── crud/
│   ├── db/
│   ├── models/
│   ├── services/
│   └── main.py
├── alembic/
├── docs/
├── scripts/
├── tests/
├── .env.example
├── alembic.ini
├── docker-compose.yaml
├── Dockerfile
├── pyproject.toml
└── README.md
Enter fullscreen mode Exit fullscreen mode

app/main.py
This is the application entry point.

Use it to create the FastAPI() app, register routers, configure lifespan events, add middleware, and expose basic endpoints like /health.

Try not to put every route here. If main.py grows every time you add a feature, it is probably doing too much.

app/api/v1/
This folder contains your versioned API.

A common pattern is:

api/
└── v1/
    ├── endpoints/
    │   ├── login.py
    │   └── users.py
    └── router.py
Enter fullscreen mode Exit fullscreen mode

Each file in endpoints/ handles one feature or resource. For example, users.py contains user-related routes.

The router.py file combines those endpoint routers, so main.py only needs to include one versioned router:

app.include_router(api_router, prefix="/api/v1")
Enter fullscreen mode Exit fullscreen mode

Versioning early makes future changes easier.

app/core/
Use core/ for app-wide configuration and security code.

This usually includes:

Environment-based settings
Secret keys
JWT helpers
Password hashing
Authentication utilities
These concerns are used across the app, so keeping them separate avoids duplication.

app/models/
The models/ folder stores your data shapes.

Depending on your stack, this may include SQLModel models, Pydantic schemas, database table models, request models, and response models.

A useful rule: do not assume your database model should also be your API response model. For example, a user table may contain a hashed password, but your API response should not.

app/crud/
Use crud/ for reusable database operations.

Instead of writing database queries directly inside route handlers, keep them in focused functions like:

Create user
Get user by ID
Get user by email
Update user
Delete user
This keeps endpoints cleaner and database behavior easier to test.

app/db/
The db/ folder handles database setup.

It often contains the database engine, session helpers, connection logic, and initial seed data.

This keeps infrastructure concerns separate from API logic.

app/services/
Use services/ for business logic and integrations.

If a route needs to coordinate multiple steps, call an external API, send an email, or apply business rules, that logic usually belongs in a service.

Endpoints should describe the HTTP interface. Services should describe what the application actually does.

alembic/
alembic/ stores database migrations.

Models describe the current shape of your data. Migrations describe how the database changes over time.

For real applications, migrations are essential.

tests/
Your tests should be easy to find and understand.

One simple approach is to mirror your API structure:

tests/
└── api/
    └── v1/
        └── endpoints/
            ├── test_login.py
            └── test_users.py
Enter fullscreen mode Exit fullscreen mode

Start by testing behavior that users and clients depend on: login, user creation, validation, permissions, and health checks.

Supporting files
Files like Dockerfile, docker-compose.yaml, .env.example, pyproject.toml, scripts/, and docs/ are part of a healthy backend project too.

They help with local development, dependency management, deployment, documentation, and onboarding.

Generated folders like .venv/, pycache/, .pytest_cache/, and build outputs should usually stay out of your source structure and be ignored by Git.

Final thoughts
A good FastAPI structure should make the next feature easier to add.

Keep routes thin, move business logic into services, keep database logic reusable, separate config from feature code, and organize tests around behavior.

You do not need a complex architecture on day one. But once your API starts growing, a clean structure gives your project room to breathe.

Top comments (0)