Skip to main content
Flask’s URL routing system maps URL patterns to view functions. The routing rules are managed by Werkzeug’s routing system.

Adding URL Rules

route

Decorator to register a view function for a given URL rule.
@app.route("/")
def index():
    return "Hello, World!"

Signature

def route(rule: str, **options: Any) -> Callable[[T_route], T_route]
rule
str
required
The URL rule string. Can include variable parts in angle brackets, e.g., /user/<username>.
methods
list[str]
List of HTTP methods this route should accept. Defaults to ["GET"]. HEAD and OPTIONS are added automatically.
@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # Handle login
        pass
    return render_template("login.html")
endpoint
str
The endpoint name for this route. Defaults to the name of the view function. Used with url_for() to generate URLs.
@app.route("/", endpoint="home")
def index():
    return "Home"

# Later: url_for("home") returns "/"
options
Any
Additional options are passed to the underlying werkzeug.routing.Rule object. Common options include:
  • defaults: Dictionary of default values for URL variables
  • subdomain: Match a specific subdomain
  • strict_slashes: Whether to redirect trailing slashes (default: True)
  • host: Match a specific host
Returns: The decorated view function, unchanged.

add_url_rule

Register a URL rule without using a decorator. Equivalent to using @app.route().
def index():
    return "Hello, World!"

app.add_url_rule("/", view_func=index)

Signature

def add_url_rule(
    rule: str,
    endpoint: str | None = None,
    view_func: RouteCallable | None = None,
    provide_automatic_options: bool | None = None,
    **options: Any,
) -> None
rule
str
required
The URL rule string.
endpoint
str | None
default:"None"
The endpoint name to associate with the rule and view function. Used when routing and building URLs. Defaults to view_func.__name__.
view_func
RouteCallable | None
default:"None"
The view function to associate with the endpoint name. Can be None if you register the function later with the @app.endpoint() decorator.
provide_automatic_options
bool | None
default:"None"
Add the OPTIONS method and respond to OPTIONS requests automatically. Defaults to True.
options
Any
Extra options passed to the werkzeug.routing.Rule object.
Returns: None Raises: AssertionError if a view function is already registered for the endpoint.

endpoint

Decorator to register a view function for a given endpoint. Used if a rule is added without a view_func with add_url_rule().
app.add_url_rule("/ex", endpoint="example")

@app.endpoint("example")
def example():
    return "Example"

Signature

def endpoint(endpoint: str) -> Callable[[F], F]
endpoint
str
required
The endpoint name to associate with the view function.

URL Variables

URL rules can contain variable parts enclosed in angle brackets. The variable is passed as a keyword argument to the view function.
@app.route("/user/<username>")
def show_user(username):
    return f"User: {username}"

Type Converters

Converters can be used to specify the type of the variable:
@app.route("/post/<int:post_id>")
def show_post(post_id):
    # post_id is an integer
    return f"Post {post_id}"
Built-in converters:
  • string - (default) accepts any text without a slash
  • int - accepts positive integers
  • float - accepts positive floating point values
  • path - like string but also accepts slashes
  • uuid - accepts UUID strings

Multiple Variables

@app.route("/post/<int:year>/<int:month>/<int:day>")
def show_post(year, month, day):
    return f"Post from {year}-{month}-{day}"

URL Building

Use url_for() to build URLs for endpoints:
from flask import url_for

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

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

# Build URLs
with app.test_request_context():
    print(url_for("index"))  # /
    print(url_for("profile", username="john"))  # /user/john
    print(url_for("profile", username="john", page=2))  # /user/john?page=2

HTTP Methods

By default, routes only respond to GET requests. Use the methods parameter to handle other HTTP methods:
from flask import request

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # Process login
        return redirect(url_for("index"))
    # Show login form
    return render_template("login.html")
Alternatively, you can use method-specific decorators:
@app.get("/login")
def login_form():
    return render_template("login.html")

@app.post("/login")
def login_submit():
    # Process login
    return redirect(url_for("index"))
Available method decorators:
  • @app.get(rule)
  • @app.post(rule)
  • @app.put(rule)
  • @app.delete(rule)
  • @app.patch(rule)

URL Rule Options

defaults

Provide default values for URL variables:
@app.route("/users/", defaults={"page": 1})
@app.route("/users/page/<int:page>")
def show_users(page):
    return f"Page {page}"

strict_slashes

Control whether trailing slashes are enforced:
# With strict_slashes=True (default):
# /about/ and /about are different URLs

# With strict_slashes=False:
@app.route("/about", strict_slashes=False)
def about():
    return "About"  # Matches both /about and /about/

subdomain

Match specific subdomains:
@app.route("/", subdomain="api")
def api_index():
    return "API"  # Matches api.example.com/
Requires setting SERVER_NAME in the config.

host

Match specific hosts:
@app.route("/", host="api.example.com")
def api():
    return "API"

Rule Object

When you call add_url_rule(), Flask creates a werkzeug.routing.Rule object. This object contains:
  • rule: The URL rule string
  • methods: Set of HTTP methods
  • endpoint: The endpoint name
  • defaults: Default values for variables
  • subdomain: Subdomain pattern
  • host: Host pattern
  • strict_slashes: Whether trailing slashes matter
  • provide_automatic_options: Whether OPTIONS is handled automatically
You can access registered rules via app.url_map:
for rule in app.url_map.iter_rules():
    print(rule.endpoint, rule.rule, rule.methods)

Examples

REST API Routes

@app.route("/api/users", methods=["GET"])
def list_users():
    return jsonify({"users": []})

@app.route("/api/users", methods=["POST"])
def create_user():
    data = request.get_json()
    return jsonify(data), 201

@app.route("/api/users/<int:user_id>", methods=["GET"])
def get_user(user_id):
    return jsonify({"id": user_id})

@app.route("/api/users/<int:user_id>", methods=["PUT"])
def update_user(user_id):
    data = request.get_json()
    return jsonify(data)

@app.route("/api/users/<int:user_id>", methods=["DELETE"])
def delete_user(user_id):
    return "", 204

Multiple URL Patterns for One View

@app.route("/")
@app.route("/index")
@app.route("/home")
def index():
    return "Home page"

URL Patterns with Optional Parts

@app.route("/posts/")
@app.route("/posts/<int:post_id>")
def posts(post_id=None):
    if post_id is None:
        return "All posts"
    return f"Post {post_id}"

See Also

Build docs developers (and LLMs) love