Skip to main content

URL Generation with url_for

When you hardcode a URL like /login in your templates, your application becomes brittle; if you later move that logic to /auth/login, every link in your system breaks. Flask solves this with the url_for function, which generates URLs based on endpoint names (usually the name of the view function) rather than raw paths.

Basic URL Generation

In Flask, an endpoint is the name associated with a URL rule. By default, this is the name of the view function. You can generate a URL for an internal route by passing the endpoint name to url_for.

from flask import Flask, url_for

app = Flask(__name__)

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

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

with app.test_request_context():
# Generates "/"
print(url_for("index"))

# Generates "/user/alice"
print(url_for("profile", username="alice"))

Internally, Flask.url_for uses a MapAdapter from Werkzeug to build the URL. If you provide keyword arguments that are not part of the URL rule (like username in the example above), Flask automatically appends them as query string parameters.

# Generates "/?search=flask"
url_for("index", search="flask")

Working with Blueprints

When using Blueprints, endpoints are namespaced with the blueprint's name (e.g., auth.login). Inside a blueprint's view function or template, you can use a relative shortcut by prefixing the endpoint with a dot (.).

# In a blueprint named 'auth'
@bp.route("/login")
def login():
# Generates "/auth/login" using the relative shortcut
return url_for(".login")

# Outside the blueprint
url_for("auth.login")

The Flask.url_for method handles this by checking the blueprint attribute of the current request context. If the endpoint starts with ., it prepends the current blueprint name:

# From src/flask/app.py
if endpoint[:1] == ".":
if blueprint_name is not None:
endpoint = f"{blueprint_name}{endpoint}"
else:
endpoint = endpoint[1:]

Generating External URLs

By default, url_for generates relative URLs (e.g., /login). To generate absolute URLs (e.g., https://example.com/login), pass _external=True. This is essential for generating links for emails or external redirects.

# Generates "http://localhost/login" (depending on config)
url_for("login", _external=True)

# Generates "https://localhost/login"
url_for("login", _external=True, _scheme="https")

Safety Rule: Flask prevents accidental insecure URLs. If you specify a _scheme, you must also set _external=True. Failing to do so raises a ValueError.

Configuration for External URLs

When generating URLs outside of an active request (for example, in a background task like Celery), Flask doesn't have a request to inspect for the domain name. In these cases, you must configure SERVER_NAME.

app.config["SERVER_NAME"] = "example.com"
app.config["PREFERRED_URL_SCHEME"] = "https"

with app.app_context():
# Generates "https://example.com/"
print(url_for("index"))

If SERVER_NAME is not set and no request context is active, url_for raises a RuntimeError.

Static Files and Anchors

Flask automatically provides a static endpoint to serve files from your application's static_folder.

# Generates "/static/style.css"
url_for("static", filename="style.css")

You can also append anchors to any generated URL using the _anchor parameter. Flask automatically quotes the anchor to ensure it is URL-safe.

# Generates "/#section-1"
url_for("index", _anchor="section-1")

# Generates "/#x%20y"
url_for("index", _anchor="x y")

Handling Build Errors

If url_for cannot find an endpoint or if required values are missing, it triggers the handle_url_build_error method. By default, this raises a werkzeug.routing.BuildError. You can customize this behavior by providing a function to app.url_build_error_handlers to handle specific failures gracefully.

# src/flask/app.py implementation detail
try:
rv = url_adapter.build(
endpoint,
values,
method=_method,
url_scheme=_scheme,
force_external=_external,
)
except BuildError as error:
return self.handle_url_build_error(error, endpoint, values)

Subdomain Handling

If your application uses subdomains, url_for can generate URLs across them. This requires SERVER_NAME to be configured.

app.config["SERVER_NAME"] = "example.com"

@app.route("/", subdomain="api")
def api_index():
return "API"

with app.test_request_context():
# Generates "http://api.example.com/"
print(url_for("api_index", _external=True))

When subdomain_matching is enabled on the Flask instance, the create_url_adapter method ensures that the MapAdapter is bound with the correct subdomain information from the request or configuration.