flask

Flask Framework Guide

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "flask" with this command: npx skills add ar4mirez/samuel/ar4mirez-samuel-flask

Flask Framework Guide

Applies to: Flask 3.0+, REST APIs, Microservices, Web Applications Language Guide: @.claude/skills/python-guide/SKILL.md

Overview

Flask is a lightweight WSGI web framework providing the basics for building web applications while allowing flexibility in choosing components.

Use Flask when:

  • Building microservices or small-to-medium APIs

  • You want flexibility to choose your own ORM, auth, etc.

  • Rapid prototyping is needed

  • You prefer explicit over implicit behavior

Consider alternatives when:

  • You need async support (use FastAPI or Quart)

  • You want batteries-included (use Django)

  • High performance async is critical (use FastAPI)

Guardrails

Flask-Specific Guidelines

  • Use the application factory pattern (never use global app instances)

  • Use blueprints for modular routing

  • Use Flask extensions appropriately (init in extensions.py)

  • Configure via environment variables with class-based config

  • Use Marshmallow for validation/serialization

  • Implement proper error handlers for all error types

  • Use Flask-Migrate for database migrations

  • Use Flask-JWT-Extended for authentication

Security Guidelines

  • Never store plain passwords (use werkzeug.security)

  • Use environment variables for all secrets

  • Implement proper authentication and authorization

  • Validate all user input with Marshmallow schemas

  • Use HTTPS in production

  • Set secure cookie options (HTTPONLY, SECURE, SAMESITE)

  • Sanitize all database queries via SQLAlchemy ORM

  • Configure CORS restrictively in production

Testing Guidelines

  • Use pytest with Flask test client

  • Use fixtures for test data and app context

  • Test both success and error cases for every endpoint

  • Mock external services (never call real APIs in tests)

  • Use a separate test database

  • Coverage target: >80% for business logic

Project Structure

myproject/ ├── app/ │ ├── init.py # Application factory │ ├── config.py # Configuration classes │ ├── extensions.py # Flask extensions (single init point) │ ├── models/ │ │ ├── init.py │ │ ├── base.py # Base model class with mixins │ │ └── user.py │ ├── api/ │ │ ├── init.py # API blueprint registration │ │ ├── users.py # User endpoints │ │ └── auth.py # Auth endpoints │ ├── services/ │ │ ├── init.py │ │ └── user_service.py # Business logic (no Flask imports) │ ├── schemas/ │ │ ├── init.py │ │ └── user.py # Marshmallow schemas │ └── utils/ │ ├── init.py │ ├── errors.py # Custom exceptions and handlers │ └── decorators.py # Auth and role decorators ├── migrations/ # Alembic migrations (via Flask-Migrate) ├── tests/ │ ├── conftest.py # Fixtures: app, client, db_session │ ├── test_api/ │ │ └── test_users.py │ └── test_services/ │ └── test_user_service.py ├── .env.example ├── requirements.txt ├── requirements-dev.txt ├── pyproject.toml └── run.py # Entry point

Key conventions:

  • app/init.py contains create_app() factory only

  • app/extensions.py centralizes all extension instances

  • app/services/ holds business logic, no Flask imports

  • app/schemas/ holds Marshmallow validation/serialization

  • app/utils/errors.py defines custom exceptions and handlers

Application Factory

Always use the factory pattern. Never use a global app = Flask(name) .

"""Flask application factory.""" from flask import Flask

from app.config import config from app.extensions import db, migrate, ma, jwt, cors

def create_app(config_name: str = "development") -> Flask: """Create and configure the Flask application.""" app = Flask(name) app.config.from_object(config[config_name])

register_extensions(app)
register_blueprints(app)
register_error_handlers(app)
register_commands(app)

return app

def register_extensions(app: Flask) -> None: """Initialize Flask extensions.""" db.init_app(app) migrate.init_app(app, db) ma.init_app(app) jwt.init_app(app) cors.init_app(app)

def register_blueprints(app: Flask) -> None: """Register Flask blueprints.""" from app.api import api_bp app.register_blueprint(api_bp, url_prefix="/api/v1")

def register_error_handlers(app: Flask) -> None: """Register error handlers.""" from app.utils.errors import ( handle_app_error, handle_validation_error, handle_not_found, handle_internal_error, ) from marshmallow import ValidationError

app.register_error_handler(ValidationError, handle_validation_error)
app.register_error_handler(404, handle_not_found)
app.register_error_handler(500, handle_internal_error)

def register_commands(app: Flask) -> None: """Register CLI commands.""" from app.commands import seed_db app.cli.add_command(seed_db)

Blueprints

Organize routes into blueprints. Register them in the factory.

"""API blueprint registration.""" from flask import Blueprint

api_bp = Blueprint("api", name)

Import routes to register them

from app.api import users, auth # noqa: F401, E402

Blueprint endpoints follow REST conventions:

Method Route Handler Description

GET /resources

get_resources()

List with pagination

GET /resources/<id>

get_resource(id)

Get single resource

POST /resources

create_resource()

Create resource

PATCH /resources/<id>

update_resource(id)

Partial update

DELETE /resources/<id>

delete_resource(id)

Delete resource

Configuration

Use class-based configuration with environment variable overrides.

"""Application configuration.""" import os from datetime import timedelta from typing import Type

class Config: """Base configuration.""" SECRET_KEY = os.getenv("SECRET_KEY", "change-in-production") SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = { "pool_pre_ping": True, "pool_recycle": 300, } JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", SECRET_KEY) JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=1) JWT_REFRESH_TOKEN_EXPIRES = timedelta(days=30) CORS_ORIGINS = os.getenv("CORS_ORIGINS", "*").split(",")

class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = os.getenv( "DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/myapp_dev" ) SQLALCHEMY_ECHO = True

class TestingConfig(Config): TESTING = True SQLALCHEMY_DATABASE_URI = os.getenv( "TEST_DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/myapp_test" )

class ProductionConfig(Config): DEBUG = False SQLALCHEMY_DATABASE_URI = os.environ["DATABASE_URL"] SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = "Lax"

config: dict[str, Type[Config]] = { "development": DevelopmentConfig, "testing": TestingConfig, "production": ProductionConfig, }

Extensions

Centralize all Flask extension instances in a single file.

"""Flask extensions initialization.""" from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_marshmallow import Marshmallow from flask_jwt_extended import JWTManager from flask_cors import CORS

db = SQLAlchemy() migrate = Migrate() ma = Marshmallow() jwt = JWTManager() cors = CORS()

Common extensions and their purposes:

Extension Purpose

Flask-SQLAlchemy ORM and database integration

Flask-Migrate Alembic database migrations

Flask-Marshmallow Serialization and validation

Flask-JWT-Extended JWT authentication

Flask-CORS Cross-origin resource sharing

Flask-Limiter Rate limiting

Flask-Caching Response and data caching

Flask-Mail Email sending

Error Handling

Define a custom exception hierarchy and register handlers.

"""Custom exceptions and error handlers.""" from flask import jsonify

class AppError(Exception): """Base application error.""" def init(self, message: str, status_code: int = 400): super().init(message) self.message = message self.status_code = status_code

class NotFoundError(AppError): def init(self, message: str = "Resource not found"): super().init(message, status_code=404)

class UnauthorizedError(AppError): def init(self, message: str = "Unauthorized"): super().init(message, status_code=401)

class ForbiddenError(AppError): def init(self, message: str = "Forbidden"): super().init(message, status_code=403)

class ConflictError(AppError): def init(self, message: str = "Conflict"): super().init(message, status_code=409)

def handle_validation_error(error): return jsonify({"error": "Validation error", "details": error.messages}), 400

def handle_app_error(error: AppError): return jsonify({"error": error.message}), error.status_code

def handle_not_found(error): return jsonify({"error": "Not found"}), 404

def handle_internal_error(error): return jsonify({"error": "Internal server error"}), 500

Jinja2 Templates

When building server-rendered pages (not just APIs):

  • Templates live in app/templates/ with a base.html layout

  • Use template inheritance: {% extends "base.html" %}

  • Use {% block content %} for page-specific content

  • Escape user content automatically (Jinja2 autoescape is on by default)

  • Use url_for() for all URLs in templates

  • Keep logic out of templates; use filters and context processors

{# app/templates/base.html #} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}My App{% endblock %}</title> </head> <body> {% with messages = get_flashed_messages(with_categories=true) %} {% for category, message in messages %} <div class="alert alert-{{ category }}">{{ message }}</div> {% endfor %} {% endwith %} {% block content %}{% endblock %} </body> </html>

CLI Commands

Register custom CLI commands via Click.

"""Custom CLI commands.""" import click from flask.cli import with_appcontext from app.extensions import db

@click.command("seed-db") @with_appcontext def seed_db(): """Seed database with initial data.""" # Create initial records db.session.commit() click.echo("Database seeded.")

Commands Reference

Install dependencies

pip install -r requirements.txt pip install -r requirements-dev.txt

Set environment variables

export FLASK_APP=run.py export FLASK_ENV=development

Initialize database

flask db init flask db migrate -m "Initial migration" flask db upgrade

Seed database

flask seed-db

Run development server

flask run

Run with Gunicorn (production)

gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app('production')"

Run tests

pytest pytest -v --cov=app --cov-report=html

Lint and format

black . isort . ruff check . mypy app/

Dependencies

requirements.txt

Flask>=3.0.0 Flask-SQLAlchemy>=3.1.0 Flask-Migrate>=4.0.0 Flask-Marshmallow>=0.15.0 Flask-JWT-Extended>=4.6.0 Flask-CORS>=4.0.0 marshmallow-sqlalchemy>=0.29.0 psycopg2-binary>=2.9.9 python-dotenv>=1.0.0 gunicorn>=21.0.0

requirements-dev.txt

-r requirements.txt pytest>=7.4.0 pytest-flask>=1.2.0 pytest-cov>=4.1.0 black>=23.0.0 isort>=5.12.0 mypy>=1.5.0 ruff>=0.1.0

Advanced Topics

For detailed code examples and advanced patterns, see:

  • references/patterns.md -- Models, schemas, services, API endpoints, authentication, decorators, testing, and deployment patterns

External References

  • Flask Documentation

  • Flask-SQLAlchemy

  • Flask-Migrate

  • Flask-JWT-Extended

  • Marshmallow

  • SQLAlchemy

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

actix-web

No summary provided by upstream source.

Repository SourceNeeds Review
General

frontend-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

blazor

No summary provided by upstream source.

Repository SourceNeeds Review
General

assembly-guide

No summary provided by upstream source.

Repository SourceNeeds Review