What is Flask? Micro Web Framework Guide
Flask is a lightweight Python web framework that provides just enough structure to build web applications and APIs without imposing rigid conventions. The term "micro" refers to Flask's minimalist core philosophy: it includes only essential tools and relies on extensions for advanced features. This approach makes Flask ideal for beginners learning web development and for experienced developers building small services or APIs.
Key Takeaways
- Flask is a "micro" framework with a simple, extensible core—not limited in capability
- It provides routing (URL mapping), request/response handling, and Jinja2 templating out of the box
- Everything else (databases, forms, authentication) comes via community extensions
- Flask uses Python decorators for clean, Pythonic routing code
- Lightweight and fast, making it perfect for APIs, MVPs, and learning web development
The "Micro" Philosophy Explained
The "micro" in Flask doesn't mean your application must be small. It means Flask itself is small and doesn't assume what tools you need.
Flask's Minimalist Core
Flask provides exactly four essential components:
1. Routing: Maps incoming URL paths to Python functions. The @app.route() decorator specifies which URL triggers which function.
2. Request/Response Objects: Tools to access incoming request data (parameters, headers, form data) and craft responses.
3. Development Server: A built-in test server for development. Run your app locally without configuring a separate web server.
4. Templating: Integrated Jinja2 engine for generating dynamic HTML from templates.
Everything else is optional. Need a database? Choose SQLAlchemy, Flask-SQLAlchemy, or any other ORM. Need form validation? Use WTForms, Pydantic, or write your own. This freedom means Flask scales from a 10-line "hello world" to a large production application—you control the complexity.
Flask vs. "Batteries-Included" Frameworks
Contrast this with larger frameworks like Django, which include pre-selected tools:
| Feature | Flask | Django |
|---|---|---|
| Core size | ~100 KB | ~1.5 MB |
| Database ORM | Your choice (optional) | Built-in (Django ORM) |
| Admin interface | Your choice (optional) | Built-in |
| Form handling | Your choice (optional) | Built-in (Django Forms) |
| Learning curve | Shallow (start minimal) | Steep (learn whole stack) |
| Flexibility | Maximum (choose everything) | Limited (use Django's way) |
Django's approach suits large teams with standardized needs. Flask suits developers who want flexibility or are building something simple.
Core Features of Flask in Action
Understanding Flask Routing
Flask uses Python decorators to associate URLs with handler functions. This is Pythonic, clean, and keeps routing logic right next to the code it controls.
from flask import Flask
# Create a Flask application instance
app = Flask(__name__)
# Map the URL "/" to this function
@app.route("/")
def hello_world():
return "<h1>Hello, World!</h1>"
# Map the URL "/about" to this function
@app.route("/about")
def about_page():
return "This is the about page."
# Dynamic routes with parameters
@app.route("/user/<name>")
def greet_user(name):
return f"<h1>Hello, {name}!</h1>"
if __name__ == "__main__":
app.run(debug=True) # Start the development server
Key advantages of this pattern:
- Readability: The decorator sits directly above the function it routes
- Pythonic: Uses Python's standard decorator syntax, not configuration files
- Type-safe: Parameters are extracted from the URL path automatically
- Flexible: You can layer decorators for authentication, logging, etc.
Request and Response Handling
Flask provides request and response objects to access incoming data and shape outgoing responses:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/submit", methods=["POST"])
def submit_form():
# Access form data
name = request.form.get("name")
email = request.form.get("email")
# Return JSON response
return jsonify({
"message": f"Thank you, {name}!",
"email": email
})
@app.route("/api/data")
def get_data():
# Access query parameters
limit = request.args.get("limit", 10, type=int)
return jsonify({"data": list(range(limit))})
Why Developers Choose Flask
Simplicity and Low Barrier to Entry
Flask has one of the shortest learning curves for Python web frameworks. Beginners can build a working application in minutes:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
if __name__ == "__main__":
app.run()
Run this, visit http://localhost:5000, and you have a web application. No complex configuration, no scaffolding, no magic.
Extreme Flexibility
With Flask, you control every decision:
- Database: Use SQLAlchemy, Peewee, MongoDB, or none at all
- Templating: Jinja2 (built-in), or your own system
- Project structure: Flat or hierarchical—your call
- Security: Add authentication or leave it out
- Caching, logging, monitoring: Choose your tools
This freedom is powerful but requires discipline. You won't accidentally inherit decisions made by the framework authors.
Extensibility Through Decorators
Flask's extension system is elegant. Decorators let you wrap functionality around routes:
from functools import wraps
from flask import Flask
app = Flask(__name__)
# Custom authentication decorator
def require_auth(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not check_auth():
return "Unauthorized", 401
return f(*args, **kwargs)
return decorated_function
@app.route("/admin")
@require_auth
def admin_panel():
return "Secret admin area"
Perfect for APIs and Microservices
Flask's lightness makes it ideal for REST APIs and microservices. You can build fast, focused services without framework overhead.
from flask import Flask, jsonify, request
app = Flask(__name__)
# In-memory data store (in real apps, use a database)
items = [{"id": 1, "name": "Item 1"}]
@app.route("/api/items", methods=["GET"])
def list_items():
return jsonify(items)
@app.route("/api/items", methods=["POST"])
def create_item():
new_item = request.json
items.append(new_item)
return jsonify(new_item), 201
@app.route("/api/items/<int:item_id>", methods=["DELETE"])
def delete_item(item_id):
global items
items = [i for i in items if i["id"] != item_id]
return "", 204
Frequently Asked Questions
Can Flask scale to large applications?
Absolutely. Flask itself is simple, but you can add enterprise-grade tools (SQLAlchemy, Celery, Redis, authentication libraries). Many large companies use Flask in production. The scalability challenge isn't Flask—it's your architecture.
How does Flask handle templating?
Flask uses Jinja2, a powerful templating engine. Templates live in a templates/ folder and allow dynamic HTML generation:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/user/<name>")
def user_page(name):
return render_template("user.html", name=name)
# templates/user.html:
# <h1>Welcome, {{ name }}!</h1>
Is Flask production-ready?
Yes. Major companies (Netflix, Lyft, Pinterest early services) use Flask in production. However, the built-in development server (app.run()) should not be used for production. Deploy with a production WSGI server like Gunicorn or uWSGI, behind Nginx or Apache.
What's the difference between Flask and a REST API framework?
Flask is general-purpose (renders HTML, builds APIs, serves files). Frameworks like FastAPI are specifically optimized for REST APIs with automatic validation and documentation. Choose Flask for flexibility; choose FastAPI for API speed and type safety.
How do I handle database operations in Flask?
Flask doesn't dictate a database. Use Flask-SQLAlchemy (popular) or use SQLAlchemy directly:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
# Now use User like any SQLAlchemy model