Flask Redirect and URL For
Flask provides two tools for working with URLs inside your application: redirect() sends the user to a different page, and url_for() builds URLs from function names instead of hardcoding strings. Together, they make your app flexible and easy to maintain.
What Is a Redirect
A redirect tells the browser to go to a different URL. When your server sends a redirect response, the browser automatically loads the new URL without the user doing anything.
Browser: GET /old-page
│
Flask sends: 302 Redirect → /new-page
│
Browser: GET /new-page (automatically)
│
Flask returns: the new page content
HTTP status codes 301 and 302 both represent redirects. Code 301 means "moved permanently" (search engines update their index). Code 302 means "moved temporarily" (the default in Flask).
Using redirect()
Import redirect from Flask and return it from a view function:
from flask import Flask, redirect
app = Flask(__name__)
@app.route('/old-home')
def old_home():
return redirect('/new-home')
@app.route('/new-home')
def new_home():
return '<h1>Welcome to the New Home Page</h1>'Visiting /old-home immediately takes the browser to /new-home. The user sees the new page's content.
The Problem with Hardcoded URLs
Using redirect('/new-home') with a hardcoded string creates a maintenance problem. If you ever rename the route from /new-home to /home, you must search every file and update every reference. Hardcoded URLs scatter throughout a growing project and cause broken links.
url_for(): Build URLs from Function Names
url_for() generates a URL by looking up the endpoint name (the function name) rather than the URL string. If the URL changes, url_for() updates automatically because it references the function, not the path.
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/old-home')
def old_home():
return redirect(url_for('new_home'))
@app.route('/new-home')
def new_home():
return '<h1>Welcome to the New Home Page</h1>'url_for('new_home') looks up the function named new_home and returns its URL: /new-home. If you later change the route to /home, every url_for('new_home') call still works.
url_for('new_home')
│
Flask checks route map:
new_home → '/new-home'
│
Returns: '/new-home'
Passing Variables to url_for()
When a route contains URL variables, pass them as keyword arguments to url_for():
@app.route('/user/<int:user_id>')
def user_profile(user_id):
return f'<h1>User {user_id}</h1>'
# Elsewhere in the app:
url = url_for('user_profile', user_id=42)
# url = '/user/42'Extra keyword arguments not in the route pattern become query parameters:
url = url_for('user_profile', user_id=42, tab='posts')
# url = '/user/42?tab=posts'Common Redirect Patterns
Pattern 1: After Login, Go to Dashboard
@app.post('/login')
def login():
# validate credentials...
return redirect(url_for('dashboard'))
@app.route('/dashboard')
def dashboard():
return '<h1>Dashboard</h1>'Pattern 2: After Form Submission, Prevent Duplicate Submissions
Without a redirect, pressing the browser's Back button after a POST request re-submits the form. Redirecting after POST solves this. This pattern is called Post/Redirect/Get (PRG):
User submits form → POST /submit
│
Flask processes data
│
Flask sends 302 redirect → GET /success
│
Browser loads /success
Browser refresh replays GET (safe, not POST)
@app.post('/submit')
def submit():
# save data...
return redirect(url_for('success'))
@app.route('/success')
def success():
return '<h1>Form submitted successfully!</h1>'Generating Absolute URLs
By default, url_for() returns a relative path like /user/42. For emails, external links, or APIs, you need a full URL like https://example.com/user/42. Add _external=True:
url = url_for('user_profile', user_id=42, _external=True)
# url = 'http://127.0.0.1:5000/user/42'Linking Static Files with url_for()
url_for() also generates paths to static files. Use the special 'static' endpoint with a filename argument:
url = url_for('static', filename='css/style.css')
# url = '/static/css/style.css'In templates:
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">Summary
redirect() sends the browser to a new URL. url_for() generates URLs from function names, making your links resilient to route changes. Always use url_for() inside redirects and templates instead of writing URL strings manually. The Post/Redirect/Get pattern prevents duplicate form submissions by redirecting after every POST.
