Difficulty: Beginner
URL routing is the mechanism that maps URLs to view functions in Flask. When a user visits a URL, Flask's routing system determines which Python function should handle that request. Understanding URL rules is fundamental to building any Flask application.
Flask uses Werkzeug's routing system under the hood. When you use the @app.route() decorator, you are registering a URL rule that associates a URL pattern with a view function. Each URL rule has three components: the URL pattern (or rule), the endpoint name, and the view function.
The URL pattern is the string you pass to @app.route(). It can be a static path like '/about' or contain variable parts like '/user/<username>'. Flask matches incoming request URLs against these patterns from most specific to least specific.
The endpoint is a unique identifier for the route, defaulting to the view function's name. It is used internally by Flask and is the key you use with url_for() to generate URLs. You can override the endpoint name by passing the endpoint parameter to @app.route().
Flask has an important behavior regarding trailing slashes. If a route is defined as '/about/' (with trailing slash) and a user visits '/about' (without it), Flask will redirect them to '/about/' with a 308 redirect. However, if a route is defined as '/about' (without trailing slash) and a user visits '/about/', Flask will return a 404 error. The convention is to use trailing slashes for routes that represent 'folders' or collections, and no trailing slash for routes that represent individual resources.
You can register multiple URL rules for the same view function by stacking decorators. This is useful when you want the same handler for different URLs. You can also bypass the decorator syntax entirely and use app.add_url_rule() directly, which is the method that @app.route() calls internally.
Flask matches routes based on the order of specificity, not the order of definition. Static routes take priority over variable routes. For example, '/user/admin' will match before '/user/<username>'. This lets you define special-case routes alongside generic patterns.
Each view function name must be unique across your application (or within a blueprint). If you define two functions with the same name, even on different routes, Flask will raise an AssertionError. If you need the same function on multiple routes, stack decorators or use add_url_rule with different endpoint names.
from flask import Flask
app = Flask(__name__)
# Static routes
@app.route('/')
def index():
return 'Home Page'
@app.route('/about')
def about():
return 'About Page'
@app.route('/contact/')
def contact():
# Trailing slash: /contact redirects to /contact/
return 'Contact Page'
# Multiple decorators on one function
@app.route('/faq')
@app.route('/help')
def faq():
return 'FAQ / Help Page'
Static routes match exact URL paths. The trailing slash on '/contact/' means Flask will redirect '/contact' to '/contact/'. Multiple decorators let one function handle different URLs.
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index():
return 'Home'
@app.route('/user/<name>')
def profile(name):
return f'Profile: {name}'
@app.route('/admin', endpoint='admin_panel')
def admin():
return 'Admin'
with app.test_request_context():
print(url_for('index')) # /
print(url_for('profile', name='alice')) # /user/alice
print(url_for('admin_panel')) # /admin
Endpoints default to the function name. Use url_for() with the endpoint name to generate URLs. This decouples your code from the actual URL paths, so you can change URLs without updating every reference.
from flask import Flask
app = Flask(__name__)
def home():
return 'Home Page'
def about():
return 'About Page'
# Register routes without decorators
app.add_url_rule('/', 'home', home)
app.add_url_rule('/about', 'about', about)
# This is exactly what @app.route() does internally:
# @app.route('/about') == app.add_url_rule('/about', 'about', about_func)
app.add_url_rule() is the low-level method that @app.route() calls. It is useful when defining routes dynamically, in class-based views, or when you want to keep route registration separate from view function definitions.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Home'
@app.route('/api/users')
def users():
return 'Users'
@app.route('/api/posts')
def posts():
return 'Posts'
# Print all registered routes
with app.app_context():
for rule in app.url_map.iter_rules():
print(f'{rule.endpoint:20s} {rule.methods} {rule.rule}')
app.url_map contains all registered URL rules. Iterating it shows you every route, its endpoint, allowed methods, and URL pattern. Flask automatically registers a /static/ route for serving static files.
URL Rules, Route Decorator, Endpoint, Static Routes, Trailing Slashes