Flask is a lightweight web framework for Python. It does not ship with an ORM, admin panel, or built‑in auth; you add only what you need. That makes it a good fit for small APIs, dashboards, and prototypes where you want full control over structure. This guide gets you from zero to a running app with routes, templates, and request handling. You should be comfortable with Python basics, functions, and dictionaries.
1. When to choose Flask
Flask is “micro”: the core is small and you extend it with extensions or your own code. Use Flask when you want a simple HTTP API, a small internal tool, or a custom web app without the structure that Django imposes. For REST APIs with automatic docs and type‑based validation, FastAPI is another option. Flask is still widely used in production and has a large ecosystem (Flask‑SQLAlchemy, Flask‑Login, etc.).
2. Install Flask
Use a virtual environment so your project’s dependencies stay isolated. Create and activate it, then install Flask:
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate
pip install flask
If pip or the interpreter is not found, see Getting Started and the ModuleNotFoundError guide.
3. Minimal application
Create a file app.py in your project folder:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Hello, World!"
if __name__ == "__main__":
app.run(debug=True)
Flask(__name__) creates the application object. @app.route("/") registers a function for the root URL. When you run the file, app.run(debug=True) starts the built‑in development server with auto‑reload. Do not use debug=True in production.
4. Run the development server
From the folder that contains app.py:
# Run the script directly (if you have if __name__ == "__main__" block):
python app.py
# Or use the flask command (any OS):
# Windows (Command Prompt): set FLASK_APP=app.py
# Windows (PowerShell): $env:FLASK_APP="app.py"
# macOS / Linux: export FLASK_APP=app.py
flask run
Open http://127.0.0.1:5000/ in your browser. You should see “Hello, World!”. The default port is 5000; use flask run --port 8000 if you need another port.
5. Define more routes
Add routes by decorating functions with @app.route("..."). You can capture parts of the URL as variables:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Home Page"
@app.route("/about")
def about():
return "About Page"
@app.route("/user/<username>")
def user(username):
return f"User: {username}"
@app.route("/post/<int:post_id>")
def post(post_id):
return f"Post ID: {post_id}"
Converter types like int: ensure the path segment is an integer; otherwise Flask returns 404. Common converters: string (default), int, float, path.
6. Return HTML with templates
For real pages, use Jinja2 templates instead of building HTML in Python. Create a templates folder next to app.py, then put index.html inside it. In your view, use render_template:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template("index.html", title="Home", name="Alice")
In templates/index.html you can use {{ title }} and {{ name }}. Flask automatically escapes variables to reduce XSS; use | safe only when you trust the content. For layout reuse, see Jinja2’s extends and block in the Flask template docs.
7. Handle request data
Use the request object to read form data, query arguments, headers, and JSON body:
from flask import request
@app.route("/search")
def search():
q = request.args.get("q", "") # query param ?q=...
return f"Search: {q}"
@app.route("/submit", methods=["POST"])
def submit():
name = request.form.get("name")
email = request.form.get("email")
return f"Submitted: {name}, {email}"
# For JSON body (e.g. from fetch or requests):
# data = request.get_json()
# value = data.get("key")
If you use methods=["POST"], GET requests to that URL will get 405 unless you add "GET". Always validate and sanitise user input; see Flask’s docs on security and our JSON guide when building APIs.
8. Project structure for a growing app
Keep a small app in one file if you like. As it grows, split into packages and use blueprints:
myapp/
app.py # or application factory
config.py # configuration
requirements.txt
templates/
base.html
index.html
static/
css/
js/
For larger apps, use blueprints to group routes by feature (e.g. auth, api, admin). That keeps URLs and views organised and makes testing easier.
9. Flask vs Django vs FastAPI
Flask is minimal and flexible; you choose database, auth, and structure. Django gives you an ORM, admin, and conventions out of the box—better when you want a full content site or a large team following one structure. FastAPI is optimised for APIs: automatic OpenAPI docs, validation with Pydantic, and async support. Choose Flask when you want a small, controllable codebase and are happy to add libraries as needed.
10. Security and deployment notes
Never run the built‑in server in production. Use a production WSGI server such as Gunicorn (or Waitress on Windows). Set debug=False and use environment variables for secrets (e.g. SECRET_KEY). Disable debug and tracebacks in production to avoid leaking information. For HTTPS and static files, put Flask behind a reverse proxy (Nginx, Caddy). See Flask’s deployment docs and our PermissionError page if you hit permission issues on the server.
11. Next steps
Add a database with Flask‑SQLAlchemy or plain SQL (e.g. SQLite). Build a simple API that returns JSON and call it from the front end or from requests. Explore Flask routes and templates in more depth, then look at Django or FastAPI to compare approaches.