Your first Flask app
Routes, view functions, the development server, and how Flask decides which function handles a request.
The smallest app
# app.py
from flask import Flask
app = Flask(__name__)
@app.get("/")
def index():
return "Hello, world"
@app.get("/health")
def health():
return {"ok": True} # dict -> JSON automatically
if __name__ == "__main__":
app.run(debug=True)pip install flask
python app.py # http://127.0.0.1:5000
flask --app app run --debug # the CLI way⚠️
debug=True gives you an interactive traceback in the browser — and lets anyone who finds the page run code on your machine. Development only, never in production.Routing rules
@app.get("/posts/<int:post_id>") # converter: int, float, path, uuid
def show_post(post_id):
return f"Post {post_id}"
@app.route("/submit", methods=["GET", "POST"])
def submit():
...
@app.get("/files/<path:subpath>") # path allows slashes
def serve(subpath):
...
# build a URL instead of hardcoding it
from flask import url_for
url_for("show_post", post_id=42) # /posts/42Flask matches the most specific rule and raises on ambiguity. Using url_for means renaming a route does not break your templates and links.
Configuration and project layout
myapp/
app.py
config.py
templates/
static/
requirements.txtimport os
app.config.update(
SECRET_KEY=os.environ["SECRET_KEY"], # required for sessions and flash
DEBUG=False,
JSON_SORT_KEYS=False,
)💡
Read secrets from the environment. A
SECRET_KEY committed to Git lets anyone forge session cookies.FAQ
Flask or FastAPI?
Flask when you want a small, explicit framework and HTML templates; FastAPI when you want typed request models, automatic OpenAPI docs and async-first APIs.
Why does my code change not take effect?
The reloader was off. Run with
--debug, or restart the server.Related
Templates with Jinja2 Forms, sessions and errors
Last refreshed 2026-09-18.