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.