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
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_URLorSECRET_KEY). instancefolder — 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:
- Create the project folder and virtual environment — isolate dependencies.
- Set up the application package (
app/) with__init__.pycontaining the factory. - Add a configuration module (
config.py) with environment-specific classes. - Create blueprints for each feature — e.g.,
authandmain— each with its own routes and templates. - Organize models and services in separate packages for database and business logic.
- Place templates and static files — global ones in
app/templatesandapp/static, feature-specific ones inside the blueprint's folder. - Create the entry point (
run.py) to run the app during development. - Set up tests in a
tests/folder, using the factory to create fresh app instances. - Handle instance-specific config with the
instancefolder 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:
- By feature (recommended):
blueprints/auth/,blueprints/main/— logical grouping. - By function:
blueprints/routes.pyandblueprints/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.pyyears into a project — leads to untestable, unmaintainable code. Start structuring early. - Forgetting to set
template_folderorstatic_folderin 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
instancefolder with secret keys or database URIs. Always use environment variables and.gitignore.
Variations
- Organize blueprints by feature (auth, admin, api) instead of by function (routes, models).
- Use Flask extensions like Flask-SQLAlchemy and Flask-Migrate, which impose their own folder conventions for models and migrations.
- 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
instancefolder 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.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.