Skip to main content
This guide will walk you through creating your first Flask application. By the end, you’ll understand the basics of routing, templates, and running a development server.
Make sure you have installed Flask before continuing.

A Minimal Application

A minimal Flask application looks like this:
app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, World!"
1

Save the code

Save the code above as app.py in your project directory.
2

Run the application

flask run
You’ll see output like:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
3

View in browser

Open http://127.0.0.1:5000/ in your browser to see “Hello, World!” displayed.

What This Does

  1. Flask(__name__) - Creates an instance of the Flask application. The __name__ argument helps Flask locate resources like templates and static files.
  2. @app.route("/") - A decorator that tells Flask which URL should trigger the function. In this case, the root URL /.
  3. hello() - The view function that returns the response. Flask converts the return value into an HTTP response.

Routing

Routing maps URLs to Python functions. Flask makes this simple with the @app.route() decorator.

Basic Routes

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Index Page"

@app.route("/hello")
def hello():
    return "Hello, World!"

Variable Rules

You can capture values from the URL using variable rules:
@app.route("/user/<username>")
def show_user_profile(username):
    return f"User: {username}"

@app.route("/post/<int:post_id>")
def show_post(post_id):
    return f"Post ID: {post_id}"
Supported converters:
  • string - Default, accepts any text without slashes
  • int - Accepts positive integers
  • float - Accepts positive floating point values
  • path - Like string but also accepts slashes
  • uuid - Accepts UUID strings

HTTP Methods

By default, routes only respond to GET requests. You can handle different HTTP methods:
from flask import request

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        return "Processing login..."
    else:
        return "Login form"
Or use method-specific decorators:
@app.get("/data")
def get_data():
    return "Getting data"

@app.post("/data")
def post_data():
    return "Posting data"

Rendering Templates

Flask uses the Jinja2 template engine to render HTML templates. Templates allow you to separate your presentation logic from your Python code.

Project Structure

Create a templates folder in your project directory:
/myproject
    app.py
    /templates
        base.html
        index.html

Base Template

Create a base template that other templates can extend:
templates/base.html
<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
  <h1><a href="{{ url_for('index') }}">My App</a></h1>
  <ul>
    <li><a href="{{ url_for('about') }}">About</a></li>
  </ul>
</nav>
<section class="content">
  <header>
    {% block header %}{% endblock %}
  </header>
  {% for message in get_flashed_messages() %}
    <div class="flash">{{ message }}</div>
  {% endfor %}
  {% block content %}{% endblock %}
</section>

Child Template

templates/index.html
{% extends 'base.html' %}

{% block header %}
  <h1>{% block title %}Welcome{% endblock %}</h1>
{% endblock %}

{% block content %}
  {% for post in posts %}
    <article class="post">
      <header>
        <div>
          <h1>{{ post['title'] }}</h1>
          <div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%Y-%m-%d') }}</div>
        </div>
      </header>
      <p class="body">{{ post['body'] }}</p>
    </article>
    {% if not loop.last %}
      <hr>
    {% endif %}
  {% endfor %}
{% endblock %}

Rendering Templates in Views

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index():
    posts = [
        {"title": "First Post", "username": "John", "created": datetime.now(), "body": "Hello world!"},
        {"title": "Second Post", "username": "Jane", "created": datetime.now(), "body": "Another post!"}
    ]
    return render_template("index.html", posts=posts)

Request Data

Access data from incoming requests using the request object:
from flask import Flask, request

app = Flask(__name__)

@app.route("/submit", methods=["POST"])
def submit():
    # Form data
    username = request.form["username"]
    
    # Query parameters
    page = request.args.get("page", 1, type=int)
    
    # JSON data
    data = request.get_json()
    
    return "Data received"

URL Building

Use url_for() to build URLs for your functions:
from flask import Flask, url_for, redirect

app = Flask(__name__)

@app.route("/")
def index():
    return "Index"

@app.route("/user/<username>")
def profile(username):
    return f"Profile: {username}"

@app.route("/redirect-to-profile")
def redirect_to_profile():
    # Generates URL like /user/john
    return redirect(url_for("profile", username="john"))

Running the Development Server

Basic Usage

flask run

Enable Debug Mode

Debug mode provides helpful error messages and auto-reloading:
flask run --debug
Never use debug mode in production! It allows arbitrary code execution from the browser.

Custom Host and Port

flask run --host=0.0.0.0 --port=8080
This makes the server publicly accessible on port 8080.

Specifying the Application

If your application is not named app.py or wsgi.py, specify it:
flask --app myapp run
For an application factory pattern:
flask --app "myapp:create_app()" run

Application Factory Pattern

For larger applications, use the factory pattern to create your app:
myapp/__init__.py
import os
from flask import Flask

def create_app(test_config=None):
    """Create and configure an instance of the Flask application."""
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        # a default secret that should be overridden by instance config
        SECRET_KEY="dev",
        DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
    )

    if test_config is None:
        # load the instance config, if it exists, when not testing
        app.config.from_pyfile("config.py", silent=True)
    else:
        # load the test config if passed in
        app.config.update(test_config)

    # ensure the instance folder exists
    os.makedirs(app.instance_path, exist_ok=True)

    @app.route("/hello")
    def hello():
        return "Hello, World!"

    return app
Run it with:
flask --app myapp run --debug

Next Steps

You now know the basics of Flask! Here are some topics to explore next:

Templates

Learn more about Jinja2 templating

Tutorial

Build a complete blog application

Blueprints

Organize your application structure

API Reference

Explore the complete Flask API

Build docs developers (and LLMs) love