Structuring FastAPI Projects for Maintainability and Scalability

Hi, I’m Fast Eddy! As a backend web developer who spends most of my time with FastAPI, I’ve learned that maintainable, scalable project structure is the foundation of any robust API. Let’s break down how you can structure your FastAPI projects so they remain clear, scalable, and ready for growth—whether you’re working solo or leading a larger team.

Why Project Structure Matters

FastAPI makes it super easy to spin up endpoints fast. But as your project grows, you’ll quickly hit organizational hiccups if you stick with the default, single-file approach. Taking a bit of time to set up a thoughtful structure upfront can save countless headaches (and refactors) later.

Common Project Structure

Let’s look at a directory layout that works well for most mid- to large-sized projects:

myfastapiapp/
│
├── app/
│   ├── __init__.py
│   ├── main.py            # Application entrypoint
│   ├── api/               # Routers and API logic
│   │   ├── __init__.py
│   │   └── v1/
│   │       ├── __init__.py
│   │       ├── endpoints/
│   │       │   ├── __init__.py
│   │       │   ├── users.py
│   │       │   └── items.py
│   │       └── dependencies.py
│   ├── core/              # Core app configs, settings, security, etc.
│   │   ├── __init__.py
│   │   ├── config.py
│   │   └── security.py
│   ├── models/            # Pydantic and ORM models
│   │   ├── __init__.py
│   │   ├── user.py
│   │   └── item.py
│   ├── crud/              # CRUD operations, DB logic
│   │   ├── __init__.py
│   │   ├── user.py
│   │   └── item.py
│   ├── db/                # Database session, metadata
│   │   ├── __init__.py
│   │   └── session.py
│   └── utils/             # Utility/helper functions
│       ├── __init__.py
│       └── email.py
├── tests/
│   ├── __init__.py
│   ├── test_users.py
│   └── test_items.py
├── alembic/               # Database migrations (if using Alembic)
├── .env
├── requirements.txt
├── Dockerfile
└── README.md

Key Principles

1. Separation of Concerns:

  • Keep endpoints, business logic, and data models in their own modules.
  • Avoid massive files that conglomerate unrelated logic.

2. API Versioning:

  • Nest endpoints under /api/v1/ (and so on) directories from the start. This simplifies future upgrades and backward compatibility.

3. Dependency Injection:

  • Place shared dependencies (auth, DB sessions, etc.) in dedicated dependencies.py files.

4. Config Management:

  • House settings and startup logic in core/ for better organization and single sourcing of truth (read more in my previous article: "Managing Environment Variables in FastAPI Applications").

5. Utility Layer:

  • Utilities or helpers go in a utils/ folder to keep business logic clean.

Practical Example: Adding a User Endpoint

Suppose you want to add /users endpoints. Here’s what you’d do:

  • Create a users.py file under both models/ and crud/ for the schemas and CRUD functions.
  • Add endpoint logic to api/v1/endpoints/users.py.
  • Route all /users requests from your main router file (api/v1/__init__.py).
  • Wire up dependencies in api/v1/dependencies.py as needed.

Scaling Up

This structure supports the addition of:

  • More teams or developers (clear file boundaries help code reviews and onboarding)
  • New API versions
  • Plugins or third-party integrations
  • Automated testing in the tests/ directory

Summary

Properly structuring your FastAPI application sets you up for easier maintenance, painless scaling, and happier developers. A clear directory layout is the unsung hero of a project’s success.

Have your own best practices or run into structure headaches recently? Share your thoughts below or ping me on Dev Chat!

— Fast Eddy

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *