The Perfect Project Structure: Scalable Application Layout

The Perfect Project Structure: Scalable Application Layout

Move beyond single-file apps. Learn how to organize FastAPI projects using feature-based modularity for long-term maintainability.

The Perfect Project Structure

When you first start with FastAPI, you likely put everything in main.py. This is fine for a "Hello World" app, but as your project grows to 50 endpoints and 10 database tables, main.py becomes a "Spaghetti Monster"—hard to read, impossible to test, and a nightmare to maintain.

In this lesson, we learn how the pros organize their code.


1. Single-File vs. Modular Apps

The Single-File Approach (Limit: ~100 lines)

Used for demos, prototypes, or extremely simple utility APIs.

  • Pros: Easy to start, no imports to manage.
  • Cons: Poor scalability, hard to navigate.

The Modular Approach (Production Standard)

Separating code by its responsibility (database, routes, schemas) or by feature (users, items, payments).

  • Pros: Clean separation of concerns, easier testing, team-friendly.
  • Cons: Requires a solid understanding of Python imports.

2. Feature-Based Organization

The gold standard for production-grade FastAPI apps is Feature-Based Organization. Instead of putting all routes in one folder and all models in another, you group everything related to a specific feature together.

The Recommended Directory Structure:

/app
    main.py             # Entry point: initializes FastApi, includes routers
    /api
        /v1             # Versioning your API
            api.py      # Combines all module routers
            /endpoints
                users.py
                items.py
    /core
        config.py       # Pydantic Settings
        security.py     # JWT, password hashing
    /models             # SQLAlchemy/SQLModel database models
    /schemas            # Pydantic models (data validation)
    /crud               # Create, Read, Update, Delete logic
    /db
        base.py         # Database engine and session setup

3. The Power of APIRouter

FastAPI provides a tool called APIRouter. Think of it as a "Mini FastAPI app" that you can plug into your main application.

Instead of writing @app.get everywhere, you write @router.get in your sub-files.

How it looks in code:

api/v1/endpoints/users.py:

from fastapi import APIRouter

router = APIRouter()

@router.get("/")
def get_users():
    return [{"user": "Admin"}]

main.py:

from fastapi import FastAPI
from app.api.v1.endpoints import users

app = FastAPI()

# Include the router in the main app!
app.include_router(users.router, prefix="/users", tags=["users"])

4. Why This Matters for Teams

When you organized by feature:

  • Frontend engineers know exactly where to find the source of truth for an endpoint.
  • Backend engineers can work on the users module without accidentally breaking the payments module.
  • Reviewers can see a clear path of logic during PRs.

Visualizing the Modular Flow

graph TD
    A["Main.py"] --> B["APIRouter (Global)"]
    B --> C["User Router"]
    B --> D["Item Router"]
    
    C --> C1["GET /users"]
    C --> C2["POST /users"]
    
    D --> D1["GET /items"]
    D --> D2["PUT /items"]

Summary

  • Modularize early: Don't wait for your file to grow to 1,000 lines.
  • Feature-First: Group related code together.
  • APIRouter: Use it to keep your main.py clean and focused on initialization.

In the next lesson, we’ll look at Environment Management and Dependency Isolation—ensuring your app runs the same on your laptop as it does in the cloud.


Exercise: The Folder Challenge

If you were building a Blog Application, which files would you expect to see inside a /posts feature folder using the modular approach?

Subscribe to our newsletter

Get the latest posts delivered right to your inbox.

Subscribe on LinkedIn