Flask
Python
web development
dynamic URLs
url_for

Create dynamic URLs in Flask with url_for

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Flask, url_for() is the standard way to build links to routes, static files, and external endpoints. Instead of hardcoding paths such as /users/alice, you refer to the endpoint name and let Flask generate the final URL from the routing table.

Build URLs From Endpoint Names

Every Flask route has an endpoint name. By default, that name is the view function name. url_for() looks up that endpoint and fills in any required path variables.

python
1from flask import Flask, url_for
2
3app = Flask(__name__)
4
5@app.route("/users/<username>")
6def profile(username):
7    return f"Profile for {username}"
8
9with app.test_request_context():
10    print(url_for("profile", username="alice"))

The output is /users/alice.

This is safer than hardcoding URL strings because route changes only need to be updated in one place. That becomes especially valuable once blueprints and redirects are spread across a larger application.

Use Path Variables and Query Parameters Correctly

If the route declares a variable, you must provide it. Extra arguments that do not belong to the route become query parameters.

python
1from flask import Flask, request, url_for
2
3app = Flask(__name__)
4
5@app.route("/posts/<int:post_id>")
6def post_detail(post_id):
7    return f"Post {post_id}"
8
9@app.route("/search")
10def search():
11    query = request.args.get("q", "")
12    page = request.args.get("page", "1")
13    return f"Searching for {query} on page {page}"
14
15with app.test_request_context():
16    print(url_for("post_detail", post_id=10))
17    print(url_for("search", q="flask", page=2))

The generated URLs are /posts/10 and /search?q=flask&page=2.

Use path segments for values that identify the resource itself, and query parameters for optional filters, sorting, or pagination.

Use url_for() in Templates, Redirects, and Static Files

Inside Jinja templates, url_for() is available automatically, so navigation links and asset paths should almost always use it.

html
1<nav>
2  <a href="{{ url_for('profile', username='alice') }}">Profile</a>
3  <link rel="stylesheet" href="{{ url_for('static', filename='site.css') }}">
4</nav>

The same applies in view functions when you redirect after a form submission.

python
1from flask import Flask, redirect, url_for
2
3app = Flask(__name__)
4
5@app.route("/login")
6def login():
7    return redirect(url_for("profile", username="alice"))

Using url_for() here avoids hardcoded redirect targets and keeps route changes centralized. It also makes refactors safer when the route path changes but the endpoint name stays stable.

Work With Blueprints, External URLs, and Context

When routes live inside blueprints, the endpoint name is prefixed with the blueprint name.

python
1from flask import Blueprint, Flask, url_for
2
3admin = Blueprint("admin", __name__)
4
5@admin.route("/dashboard")
6def dashboard():
7    return "Admin dashboard"
8
9app = Flask(__name__)
10app.register_blueprint(admin, url_prefix="/admin")
11
12with app.test_request_context(base_url="https://example.com"):
13    print(url_for("admin.dashboard"))
14    print(url_for("admin.dashboard", _external=True))

The first call returns /admin/dashboard. The second returns an absolute URL such as https://example.com/admin/dashboard.

Absolute URLs are useful in emails, webhook configuration, and any integration that runs outside the current browser request. If url_for() raises an error in tests or scripts, the cause is often missing application or request context rather than a missing route.

A small app.test_request_context() block is also a good debugging tool. It lets you verify endpoint names and generated URLs from a shell or unit test without starting the whole development server reliably.

That is one more reason endpoint names are preferable to hardcoded paths. They give you one routing vocabulary to use across templates, redirects, tests, and CLI scripts.

That consistency becomes more valuable as the application grows and routing complexity increases.

Common Pitfalls

  • Passing the URL pattern string instead of the endpoint name.
  • Forgetting to provide a required route variable, which causes a build error.
  • Calling url_for() outside an application or request context.
  • Mixing up query parameters and path variables.
  • Hardcoding asset paths instead of using url_for('static', filename='...').

Summary

  • Use url_for() so links stay aligned with Flask routes.
  • Pass required route variables directly and let extra values become query parameters.
  • Use url_for() in templates, redirects, and static file references instead of hardcoded strings.
  • Use blueprint-qualified endpoint names and _external=True when the situation requires them.

Course illustration
Course illustration

All Rights Reserved.