Dynamic Routes & Variables

Reviewed & published by Brayan K

A dynamic route is a route with a variable part in its URL, written in angle brackets like /user/<name> — the value in that spot is captured from the URL and passed straight into your view function.

Part of the free Flask course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

In this lesson you'll capture values from URLs, use converters to control their type, and build flexible pages that respond to many addresses with a single function. Run any example locally with flask run.

What You'll Learn in This Lesson

1 Capturing a Value From the URL

A dynamic route has a piece of its path wrapped in angle brackets. The text inside the brackets is a variable name. When a request matches, Flask pulls that part of the URL out and passes it to your view function as an argument with the same name.

In the example below, visiting /user/Ada calls profile(username="Ada"). The same single function handles /user/Grace, /user/Linus, and any other name.

# dynamic.py — capture a value from the URL
from flask import Flask

app = Flask(__name__)

# <username> captures whatever follows /user/ and passes
# it into the function as the 'username' argument.
@app.route("/user/<username>")
def profile(username):
    return f"<h1>Profile page for {username}</h1>"

# Simulate a few requests to see the captured value used:
for name in ["Ada", "Grace", "Linus"]:
    print(profile(name))

# Run locally with: flask run, then visit /user/Ada

# ✅ Expected output:
# <h1>Profile page for Ada</h1>
# <h1>Profile page for Grace</h1>
# <h1>Profile page for Linus</h1>

2 Converters: Controlling the Type

By default a captured value is a string. A converter lets you require a specific type by writing it before the variable name, like <int:post_id>. Flask both checks the value matches and converts it for you — so post_id arrives as a real Python int.

If the URL doesn't match the converter (for example /post/hello when an int is expected), Flask returns a 404 instead of calling your function.

# Using the int converter
from flask import Flask

app = Flask(__name__)

# <int:post_id> only matches whole numbers, and post_id
# arrives as a real int (not a string).
@app.route("/post/<int:post_id>")
def show_post(post_id):
    # We can do math because post_id is an integer
    return f"<h1>Post #{post_id}</h1><p>Next post: {post_id + 1}</p>"

print(show_post(5))     # -> Post #5, next 6
print(show_post(42))    # -> Post #42, next 43

# /post/hello would NOT match -> Flask returns 404

# ✅ Expected output:
# <h1>Post #5</h1><p>Next post: 6</p>
# <h1>Post #42</h1><p>Next post: 43</p>

3 Multiple Variables in One Route

A route can capture more than one value. Each angle-bracket section becomes one argument, in order. The route below captures a category as text and an item id as an integer.

# Two captured values, two converters
from flask import Flask

app = Flask(__name__)

# /shop/books/3 -> category="books", item_id=3
@app.route("/shop/<category>/<int:item_id>")
def product(category, item_id):
    return f"<h1>{category.title()} item #{item_id}</h1>"

print(product("books", 3))    # Books item #3
print(product("toys", 17))    # Toys item #17

# Run locally with flask run, then visit /shop/books/3

# ✅ Expected output:
# <h1>Books item #3</h1>
# <h1>Toys item #17</h1>

The order matters: the first bracket maps to the first parameter, the second bracket to the second. The names just need to match between the route and the function signature.

🔬 Anatomy of a Dynamic Route

PatternWhat it captures
/user/<name>Any text as a string, passed as name
/post/<int:id>A whole number, passed as an int
/price/<float:amt>A decimal, passed as a float
/files/<path:p>Text that may contain slashes

🎯 Your Turn: Fill in the Blanks

Finish a route that greets a user by name and another that shows a numbered order. Replace each ___.

# 🎯 YOUR TURN: replace each ___ to finish the routes
from flask import Flask

app = Flask(__name__)

# Greet any name from the URL
@app.route("/hello/<___>")          # capture a name
def greet(name):
    return f"<h1>Hello, {___}!</h1>" # use the captured value

# Show an order by its number (must be an integer)
@app.route("/order/<___:order_id>") # require an integer
def order(order_id):
    return f"<h1>Order {order_id}</h1>"

print(greet("Sam"))
print(order(99))

Common Errors & Quick Reference

❌ TypeError: profile() missing 1 required positional argument

Your view function takes a parameter but you forgot the matching variable in the route, or the names don't match. The bracket name and the parameter name must be identical.

❌ 404 Not Found for /post/abc

The converter rejected the value. <int:post_id> only matches numbers, so a non-numeric value never reaches your function — that's working as intended.

GoalRoute pattern
Capture text/user/<name>
Capture an integer/post/<int:id>
Capture a decimal/price/<float:amt>
Capture a path/files/<path:p>

🏆 Mini Challenge: A Blog URL Scheme

Design routes for a simple blog.

# 🏆 Mini Challenge: a blog URL scheme
from flask import Flask

app = Flask(__name__)

@app.route("/author/<name>")
def author(name):
    return f"<h1>Articles by {name}</h1>"

@app.route("/article/<int:id>")
def article(id):
    return f"<h1>Article #{id}</h1>"

# TODO: a comment under a specific article
@app.route("/article/<int:id>/comments/<int:c>")
def comment(id, c):
    return f"<h1>Comment {c} on article {id}</h1>"

print(author("Ada"))
print(article(7))
print(comment(7, 2))

❓ Frequently Asked Questions

Lesson complete — your routes are dynamic now!

You can capture values from URLs, convert them with <int:...> and friends, and handle several variables in one route. One function can now serve thousands of URLs.

Practice quiz

How do you mark a variable part of a URL in a Flask route?

  • with curly braces {name}
  • with angle brackets <name>
  • with a colon :name
  • with parentheses (name)

Answer: with angle brackets <name>. Angle brackets like /user/<name> capture that part of the URL.

In @app.route('/user/<username>'), how is the value passed to the view?

  • as a function argument named username
  • via request.args
  • in a global variable
  • as request.form['username']

Answer: as a function argument named username. The captured segment is passed as the matching function parameter.

What type does a captured value have by default (no converter)?

  • int
  • bytes
  • string
  • list

Answer: string. Without a converter, captured URL values are strings.

Which converter requires a whole number and passes it as an int?

  • <num:id>
  • <digit:id>
  • <integer:id>
  • <int:id>

Answer: <int:id>. <int:id> matches whole numbers and converts the value to a Python int.

What happens when /post/abc hits a route declared as /post/<int:id>?

  • Flask returns a 404 Not Found
  • id becomes the string 'abc'
  • Flask raises a 500 error
  • id becomes 0

Answer: Flask returns a 404 Not Found. A non-integer does not match the converter, so the route is not selected and Flask returns 404.

Which converter matches text that may contain slashes?

  • <slash:p>
  • <path:p>
  • <any:p>
  • <url:p>

Answer: <path:p>. <path:p> accepts segments that include forward slashes.

Which converter is used for a decimal number?

  • <decimal:x>
  • <double:x>
  • <float:x>
  • <number:x>

Answer: <float:x>. <float:x> matches a decimal and passes it as a Python float.

Can a single route capture more than one variable?

  • Yes — each angle-bracket section is one argument
  • No, only one is allowed
  • Only with query strings
  • Only if both are ints

Answer: Yes — each angle-bracket section is one argument. A route like /<category>/<int:item_id> maps each bracket to a parameter in order.

For /shop/<category>/<int:item_id>, how does the view receive them?

  • both as strings
  • as request.args
  • as two parameters: category (str) and item_id (int)
  • as a single dict

Answer: as two parameters: category (str) and item_id (int). Each bracket becomes a parameter; the int converter makes item_id an int.

What must match between the route bracket and the view function?

  • the file name
  • the HTTP method
  • the return type
  • the variable/parameter name

Answer: the variable/parameter name. <username> in the route must pair with a username parameter in the function.

Continue this course

Frequently asked questions

What is a dynamic route in Flask?

A dynamic route is a route whose URL contains a variable part written in angle brackets, like /user/<name>. Whatever appears in that part of the URL is passed into your view function as an argument.

What are route converters?

Converters tell Flask what type a URL variable should be, like <int:id> for an integer or <path:subpath> for a value that may contain slashes. They both validate the value and convert it to the right Python type.

What happens if the value doesn't match the converter?

Flask returns a 404 Not Found. For example, /post/abc won't match @app.route('/post/<int:id>') because 'abc' isn't an integer, so the route simply isn't selected.

Can a route have more than one variable?

Yes. A route like /<category>/<int:item_id> has two variables, and your view function just takes two matching parameters. Each angle-bracket section becomes one argument.