Flask Project Structure Setup

Learn how to create a project structure for Flask, Python web development. Hands-on steps, troubleshooting, and next steps.

Focus: create a project structure for flask

Sponsored

You've built a couple of small Flask apps — maybe a single app.py with a few routes — and it felt fine at first. But now your routes are multiplying, templates are piling up, and every change to one file risks breaking something else. The pain is real: a flat, unstructured Flask project quickly becomes a tangled mess that's hard to debug, test, and deploy. This lesson shows you how to create a project structure for Flask that scales from a toy app to a production-ready service.

The problem this lesson solves

A single-file Flask app is like a closet where everything is thrown in — you can find your shoes, but only after digging through coats and old batteries. As your app grows, a flat structure creates three urgent problems:

  • Maintainability suffers: Every route, model, and config lives in one place. A change to one feature risks breaking another.
  • Testing becomes a nightmare: Importing your app for tests pulls in everything, making isolated unit tests hard to write.
  • Deployment friction: Without a clear separation of config, static files, and templates, moving between development, staging, and production is error-prone.

The moment you add a second feature or a second developer, the cost of a poor structure becomes crushing. You need a standard layout that separates concerns, clarifies dependencies, and follows Python and Flask conventions — so your future self (and your team) can navigate the codebase with confidence.

Core concept / mental model

Think of a well-structured Flask project as a layered cake:

  • The app factory (bottom layer) — creates your app, loads config, and registers extensions and blueprints. It's the single entry point that assembles everything.
  • Blueprints (middle layers) — group related routes, templates, and static files by feature. Each blueprint is a self-contained module.
  • Models and services (filling) — hold database models, business logic, and external API calls. These are pure Python and don't know about HTTP.
  • Templates and static files (icing) — the presentation layer, separated from logic.

Definitions you need to know

  • Application factory — a function (create_app) that builds and configures your Flask app each time it's called. This enables multiple app instances (e.g., for testing) and clean configuration.
  • Blueprint — a Flask object that groups routes and views, which you can register on any app. It's like a mini-app that plugs into the main one.
  • Config class — a Python class holding configuration variables (like DATABASE_URL or SECRET_KEY).
  • instance folder — a directory for secrets and deployment-specific config, not committed to version control.

The mental model in words

Picture a project tree where each folder has a single responsibility:

my_flask_project/
├── app/                  # The main package
│   ├── __init__.py       # create_app factory
│   ├── config.py         # Configuration classes
│   ├── models/           # Database models
│   ├── blueprints/       # Feature blueprints
│   │   ├── main/         # Main blueprint
│   │   │   ├── __init__.py
│   │   │   ├── routes.py
│   │   │   └── templates/
│   │   └── auth/         # Auth blueprint
│   │       ├── __init__.py
│   │       ├── routes.py
│   │       └── templates/
│   ├── templates/        # Global templates
│   ├── static/           # Global static files
│   └── services/         # Business logic
├── instance/             # Secret config (ignored by git)
├── tests/                # Test suite
├── requirements.txt
└── run.py                # Entry point for development

This structure ensures separation of concerns, modularity, and reusability — the same principles that make large Flask apps maintainable.

How it works step by step

Here's the logical sequence to create a Flask project structure from scratch:

  1. Create the project folder and virtual environment — isolate dependencies.
  2. Set up the application package (app/) with __init__.py containing the factory.
  3. Add a configuration module (config.py) with environment-specific classes.
  4. Create blueprints for each feature — e.g., auth and main — each with its own routes and templates.
  5. Organize models and services in separate packages for database and business logic.
  6. Place templates and static files — global ones in app/templates and app/static, feature-specific ones inside the blueprint's folder.
  7. Create the entry point (run.py) to run the app during development.
  8. Set up tests in a tests/ folder, using the factory to create fresh app instances.
  9. Handle instance-specific config with the instance folder for secrets.

Each step builds on the previous one, creating a clear cause-and-effect chain: a factory gives you testability, blueprints give you modularity, and a config module gives you deployability.

Hands-on walkthrough

Let's build a minimal but complete structure. First, set up the project and install Flask:

mkdir my_flask_project
cd my_flask_project
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install Flask

Now create the package and files. Start with the app factory:

# app/__init__.py
from flask import Flask

def create_app(config_class='app.config.DevelopmentConfig'):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Register blueprints
    from app.blueprints.main.routes import main_bp
    from app.blueprints.auth.routes import auth_bp
    app.register_blueprint(main_bp)
    app.register_blueprint(auth_bp)

    return app

Next, add a configuration module:

# app/config.py
import os

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False

Create your first blueprint:

# app/blueprints/main/routes.py
from flask import Blueprint, render_template

main_bp = Blueprint('main', __name__, template_folder='templates')

@main_bp.route('/')
def index():
    return render_template('index.html')

And the entry point:

# run.py
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(debug=True)

Run it with python run.py and visit http://127.0.0.1:5000 — you'll see the index template. Expected output in your browser: the content of index.html. In the terminal, you'll see the Flask development server logs.

For a more complex example, add a service layer and a model:

# app/services/user_service.py
def get_user_by_id(user_id):
    # In a real app, query the database here
    return {'id': user_id, 'name': 'Alice'}

Then use it in a blueprint route:

# app/blueprints/auth/routes.py
from flask import Blueprint, jsonify
from app.services.user_service import get_user_by_id

auth_bp = Blueprint('auth', __name__)

@auth_bp.route('/user/<int:user_id>')
def user(user_id):
    user = get_user_by_id(user_id)
    return jsonify(user)

Test both endpoints and verify the /user/1 route returns a JSON object.

Compare options / when to choose what

When setting up a Flask project, you have choices. Here's a comparison:

Approach Pros Cons Best for
Single file (app.py) Quick start, simple Not scalable, hard to test/debug Prototypes, tiny demos
Basic package (factory only) Testable, clear config blueprints still needed for features Small apps with one or two modules
Blueprint-heavy structure Modular, feature isolation, team-friendly More files, slight overhead Larger apps, microservices-style features
Using Flask extensions (like Flask-SQLAlchemy) Encapsulates DB logic, reduces boilerplate Ties you to the extension Most real-world apps

When to choose what:

  • Single file — for a 10-line demo or a learning exercise.
  • Factory + blueprints — as soon as you add a second feature or start writing tests. This is the sweet spot for most production apps.
  • Heavy extension integration — if you need full-featured SQLAlchemy or authentication, structure around the extension's own conventions.

Variations: Blueprint organization

You can organize blueprints in two ways:

  1. By feature (recommended): blueprints/auth/, blueprints/main/ — logical grouping.
  2. By function: blueprints/routes.py and blueprints/models.py — flat but can become monolithic.

Also, consider using a sockets/ or api/ folder for REST API blueprints if you mix server-rendered and API routes.

Troubleshooting & edge cases

ModuleNotFoundError: No module named 'app' — You're running run.py from outside the project root, or the app package isn't importable. Fix: run from the project root, or check PYTHONPATH.

TemplateNotFound: index.html — Flask can't find the template. Ensure you pass template_folder in the Blueprint or that template files are in the app's global templates folder.

ImportError: cannot import name 'create_app' — The __init__.py might be empty or have a syntax error. Check for circular imports — import blueprints inside the factory, not at module top.

Static files 404 — Ensure static_folder is set correctly, especially in blueprints. By default, a blueprint has no static folder — either set it or use the app's global static.

Factory and testing — If tests create multiple app instances, don't rely on global state. Use the factory in each test, and pass a config class that uses an in-memory database.

Instance folder not writable — On some deployments, the instance folder may have permission issues. Ensure the user running the app has write access.

What you learned & what's next

You now understand how to create a project structure for Flask that separates concerns, uses an app factory, and organizes features into blueprints. You've built a minimal but scalable layout and know when to scale from a single file to a full package. You practiced setting up config classes, templates, static files, and a testable entry point.

Next in the track: Lesson 25 covers [Next lesson title] — likely blueprints in depth or connecting a database. With this structure in place, you're ready to add persistent storage or expand your API endpoints without fear of breaking everything.

Pro tip: Always start with a factory and at least one blueprint — even for small apps. It costs little now and saves huge refactoring pain later.

Practice recap

Try refactoring a small existing Flask app (or one of your own) into this structure: create app/, add a factory, split routes into at least two blueprints, and move models/services into packages. Run your tests and confirm nothing breaks. Then add a new feature as a new blueprint and see how smoothly it integrates.

Common mistakes

  • Putting all routes in a single app.py years into a project — leads to untestable, unmaintainable code. Start structuring early.
  • Forgetting to set template_folder or static_folder in Blueprints, causing 'TemplateNotFound' or 404 errors for feature-specific assets.
  • Importing models and services at module top-level in a way that creates circular imports. Move imports inside functions or the factory.
  • Committing the instance folder with secret keys or database URIs. Always use environment variables and .gitignore.

Variations

  1. Organize blueprints by feature (auth, admin, api) instead of by function (routes, models).
  2. Use Flask extensions like Flask-SQLAlchemy and Flask-Migrate, which impose their own folder conventions for models and migrations.
  3. Adopt an Application Factory pattern without blueprints for micro-apps, but switch to blueprints when features multiply.

Real-world use cases

  • A SaaS dashboard with separate modules for authentication, billing, and reporting — each as a blueprint.
  • A REST API service where each endpoint group (users, orders, analytics) lives in its own blueprint with its own services and models.
  • An e-commerce store with separate main, checkout, and admin blueprints, each with its own templates and static assets.

Key takeaways

  • Separate concerns: app factory, config, blueprints, models, services, and templates have distinct roles.
  • Use an application factory to create configurable, testable app instances.
  • Group related routes and templates into blueprints by feature for modularity.
  • Store deployment-specific secrets in an instance folder and environment variables, never in code.
  • Start structured even for small projects — the transition cost grows quickly.
  • Test your factory-driven app by creating fresh instances with test config.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.