Difficulty: Beginner
URL building with url_for() is one of Flask's most important features. Instead of hardcoding URLs throughout your templates and code, url_for() generates URLs dynamically based on the endpoint name. This makes your application resilient to URL changes and prevents broken links.
The url_for() function takes an endpoint name as its first argument and any number of keyword arguments for URL variables. It returns the URL path as a string. If the route has variable rules, you must pass the corresponding values as keyword arguments. Any keyword arguments that do not match URL variables are appended as query string parameters.
Using url_for() has several advantages over hardcoded URLs. First, if you change a URL pattern, all url_for() calls automatically generate the correct new URL. Second, url_for() properly escapes special characters in URLs. Third, it handles the application's root path (SCRIPT_NAME) correctly when your app is mounted at a sub-path behind a reverse proxy. Fourth, it generates absolute URLs when needed (useful for emails and API responses).
To generate absolute URLs (including the scheme and host), pass _external=True to url_for(). This produces URLs like 'http://localhost:5000/about' instead of just '/about'. This is essential when generating URLs for email content, API responses, or any context where the URL will be used outside the browser's relative URL resolution.
url_for() also handles static files through the special 'static' endpoint. Flask automatically registers a route for serving files from the 'static' directory. You generate URLs to static files with url_for('static', filename='css/style.css'), which produces '/static/css/style.css'. In templates, this is how you link to CSS, JavaScript, and image files.
The redirect() function works hand-in-hand with url_for(). When you need to send the user to a different page (after form submission, after login, etc.), you call redirect(url_for('endpoint_name')). This sends a 302 redirect response. You can also specify a different status code like 301 for permanent redirects.
In Jinja2 templates, url_for() is available as a global function. You use it in href attributes, form actions, script src attributes, and anywhere else you need URLs. The pattern {{ url_for('endpoint', key=value) }} is used extensively in Flask templates.
url_for() raises a BuildError if the endpoint does not exist or if required URL variables are missing. This is actually a feature: it catches broken links at render time rather than letting them fail silently. In production, you should handle BuildError for user-generated content that might reference invalid endpoints.
from flask import Flask, url_for, redirect
app = Flask(__name__)
@app.route('/')
def index():
return f'''
<a href="{url_for('about')}">About</a>
<a href="{url_for('profile', username='alice')}">Alice</a>
<a href="{url_for('search', q='flask', page=1)}">Search</a>
'''
@app.route('/about')
def about():
return 'About page'
@app.route('/user/<username>')
def profile(username):
return f'Profile: {username}'
@app.route('/search')
def search():
return 'Search results'
url_for('about') generates '/about'. url_for('profile', username='alice') fills the variable rule to produce '/user/alice'. Extra keyword arguments like q and page are appended as query parameters.
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index():
# Static file URLs
css = url_for('static', filename='css/style.css')
js = url_for('static', filename='js/app.js')
img = url_for('static', filename='images/logo.png')
# External (absolute) URL
ext = url_for('index', _external=True)
return f'''
<link rel="stylesheet" href="{css}">
<img src="{img}" alt="Logo">
<p>Absolute URL: {ext}</p>
<script src="{js}"></script>
'''
The 'static' endpoint is automatically registered. url_for('static', filename='...') generates paths to your static directory. The _external=True parameter generates full absolute URLs including scheme and host.
from flask import Flask, url_for, redirect, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# After successful login, redirect to dashboard
return redirect(url_for('dashboard'))
return '<form method="POST"><button>Login</button></form>'
@app.route('/dashboard')
def dashboard():
return 'Welcome to your dashboard!'
@app.route('/old-page')
def old_page():
# Permanent redirect (301) to new page
return redirect(url_for('new_page'), code=301)
@app.route('/new-page')
def new_page():
return 'This is the new page'
redirect() sends a 302 (temporary) redirect by default. Use code=301 for permanent redirects. Always combine redirect() with url_for() instead of hardcoding the target URL.
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">Home</a>
<a href="{{ url_for('about') }}">About</a>
<a href="{{ url_for('profile', username='me') }}">Profile</a>
</nav>
{% block content %}{% endblock %}
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
</body>
</html>
url_for() is available in Jinja2 templates as a global function. Use it for all links, form actions, static file references, and any URL. The double curly braces {{ }} output the result into the HTML.
url_for, Static Files, External URLs, Redirect, Anchor