How to Design Scalable FastAPI Project Structures: File‑Based vs Module‑Based
This article compares two primary FastAPI project structure strategies—file‑type based and module‑function based—explaining why a well‑organized architecture improves scalability, maintainability, and team collaboration, and provides concrete directory layouts and best‑practice guidelines for building robust backend applications.
FastAPI Basics
Part 1: Blueprint
In this article we discuss two main FastAPI project structure strategies and indicate the scenarios each strategy best fits.
Why Good Structure Matters?
The most important reasons for building code based on best practices are:
Enhanced scalability : Well‑organized code can scale smoothly as the FastAPI project grows.
Improved maintainability : Readable code makes updates and fixes simple.
Simplified collaboration : Clear structure helps teams work efficiently together.
Key Principles for Building Project Structure
When building a FastAPI application, following these best practices is essential:
Separation of concerns : Separate different aspects (routes, models, business logic) to improve clarity and maintainability.
Modularity : Split the application into reusable modules to promote code reuse and organization.
Dependency injection : Decouple components via dependency injection, making code more flexible and testable, e.g., using fastapi.Dependencies .
Testability : Prioritize writing testable code, using dependency injection and mocking to ensure quality.
Structured Formats
FastAPI applications can be structured in different ways to meet various project needs.
There are two main project structure approaches: one based on file type and another based on module functionality.
1. File‑type Based Structure
In this approach, files are organized by type (e.g., API, CRUD, models, schemas, routers) as shown in the FastAPI official tutorial.
This structure suits micro‑services or smaller‑scale projects:
<code>.
├── app
│ ├── __init__.py
│ ├── main.py
│ ├── dependencies.py
│ ├── routers
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ ├── crud
│ │ ├── __init__.py
│ │ ├── item.py
│ │ └── user.py
│ ├── schemas
│ │ ├── __init__.py
│ │ ├── item.py
│ │ └── user.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── item.py
│ │ └── user.py
│ ├── external_services
│ │ ├── __init__.py
│ │ ├── email.py
│ │ └── notification.py
│ └── utils
│ ├── __init__.py
│ ├── authentication.py
│ └── validation.py
├── tests
│ ├── __init__.py
│ ├── test_main.py
│ ├── test_items.py
│ └── test_users.py
├── requirements.txt
├── .gitignore
└── README.md
</code>In this structure
app/ : Contains the main application files.
main.py : Initializes the FastAPI app.
dependencies.py : Defines dependencies used by routers.
routers/ : Holds router modules.
crud/ : Contains CRUD operation modules.
schemas/ : Holds Pydantic schema modules.
models/ : Contains database model modules.
external_services/ : Modules for interacting with external services.
utils/ : Utility modules.
tests/ : Test modules.
2. Module‑Function Based Structure
In the second method, files are organized by package functionality (e.g., authentication, user, post sub‑packages). This structure suits monolithic projects with many domains and modules, improving development efficiency by grouping all file types needed for a sub‑package together.
The layout is recommended by the FastAPI best‑practice GitHub repository.
Each package contains its own routers, schemas, models, etc.
<code>fastapi-project
├── alembic/
├── src
│ ├── auth
│ │ ├── router.py
│ │ ├── schemas.py
│ │ ├── models.py
│ │ ├── dependencies.py
│ │ ├── config.py
│ │ ├── constants.py
│ │ ├── exceptions.py
│ │ ├── service.py
│ │ └── utils.py
│ ├── aws
│ │ ├── client.py
│ │ ├── schemas.py
│ │ ├── config.py
│ │ ├── constants.py
│ │ ├── exceptions.py
│ │ └── utils.py
│ └── posts
│ ├── router.py
│ ├── schemas.py
│ ├── models.py
│ ├── dependencies.py
│ ├── constants.py
│ ├── exceptions.py
│ ├── service.py
│ └── utils.py
│ ├── config.py
│ ├── models.py
│ ├── exceptions.py
│ ├── pagination.py
│ ├── database.py
│ └── main.py
├── tests/
│ ├── auth
│ ├── aws
│ └── posts
├── templates/
│ └── index.html
├── requirements
│ ├── base.txt
│ ├── dev.txt
│ └── prod.txt
├── .env
├── .gitignore
├── logging.ini
└── alembic.ini
</code>In this structure
All domain directories are stored in the src folder.
src/ : Top‑level application package containing common models, configuration, constants, etc.
src/main.py : Root file that initializes the FastAPI app.
Each package includes its own router, schemas, models, and related files:
router.py : Core of each module, containing all endpoints.
schemas.py : Pydantic models.
models.py : Database models.
service.py : Module‑specific business logic.
dependencies.py : Router dependencies.
constants.py : Module‑specific constants and error codes.
config.py : Configuration such as environment variables.
utils.py : Non‑business utilities (response normalization, data enrichment, etc.).
exceptions.py : Module‑specific exceptions, e.g., PostNotFound , InvalidUserData .
When a package needs to import services, dependencies, or constants from another package, use explicit module names to avoid ambiguity:
<code>from src.auth import constants as auth_constants
from src.notifications import service as notification_service
from src.posts.constants import ErrorCode as PostsErrorCode
</code>Conclusion
In summary, building a solid structure for FastAPI projects is crucial for scalability, readability, and maintainability. By organizing code effectively—whether using a file‑type based layout suitable for micro‑services or a module‑function based layout for larger monoliths—you ensure the application remains manageable and adaptable to evolving requirements.
Both approaches emphasize clear organization and separation of concerns, which are key to long‑term success.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.