Flask Blueprint 라우팅 충돌
Diagnosing and resolving Flask Blueprint routing conflicts — when URL rules collide, duplicate endpoints break your application, and blueprints override each other.
Flask Blueprint 라우팅 충돌
Introduction
Flask Blueprints are the standard way to organize Flask applications into modular components. However, as your application grows and you add more blueprints, routing conflicts become inevitable. Two blueprints may define the same URL rule, or endpoints may collide, causing unpredictable behavior.
I encountered this while refactoring a monolithic Flask application in Lisbon into separate blueprint modules. The application had grown organically over two years, and the routing table had become a tangled mess of conflicting URL rules.
Environment
Flask 3.0.2
Python 3.12.3
Werkzeug 3.0.1Problem
Error 1: Duplicate endpoint names
from flask import Flask, Blueprint
api = Blueprint("api", __name__)
admin = Blueprint("admin", __name__)
@api.route("/users")
def get_users():
return "API users"
@admin.route("/users")
def get_users(): # Same function name!
return "Admin users"
app = Flask(__name__)
app.register_blueprint(api)
app.register_blueprint(admin)AssertionError: View function 'api.get_users' is already mapped
to endpoint 'get_users'Error 2: URL rule conflicts
from flask import Flask, Blueprint
web = Blueprint("web", __name__)
api = Blueprint("api", __name__)
@web.route("/api/data")
def web_api_data():
return "Web data"
@api.route("/api/data")
def api_data():
return "API data"
app = Flask(__name__)
app.register_blueprint(web)
app.register_blueprint(api)
# Both respond to /api/data — which one wins?Error 3: Blueprint prefix collision
from flask import Flask, Blueprint
users_bp = Blueprint("users", __name__)
posts_bp = Blueprint("posts", __name__)
@users_bp.route("/list")
def user_list():
return "User list"
@posts_bp.route("/list")
def post_list():
return "Post list"
app = Flask(__name__)
app.register_blueprint(users_bp, url_prefix="/api")
app.register_blueprint(posts_bp, url_prefix="/api")
# Both have /api/list — collision!Error 4: Static file conflicts
from flask import Flask, Blueprint
static_bp = Blueprint("static", __name__, static_folder="static")
another_bp = Blueprint("another", __name__, static_folder="static")
app = Flask(__name__)
app.register_blueprint(static_bp)
app.register_blueprint(another_bp)
# Both try to serve from /static/ — conflictAnalysis
Flask Blueprint routing conflicts have several causes.
Cause 1: Same endpoint names. Flask uses function names as endpoint names by default. Two blueprints defining functions with the same name create a collision, even if they are in different modules.
Cause 2: Overlapping URL rules. When two blueprints register routes for the same URL, Flask uses the last registered blueprint. This can cause silent bugs where the wrong handler is invoked.
Cause 3: URL prefix collisions. When blueprints are registered with the same prefix, their routes may overlap.
Cause 4: Missing name parameter. If you do not provide a unique name when creating a Blueprint, Flask may generate conflicting names.
Check your routing table:
from flask import Flask
app = Flask(__name__)
# Register all blueprints here...
# Print all registered rules
with app.app_context():
for rule in app.url_map.iter_rules():
endpoint = rule.endpoint
methods = rule.methods
print(f"{rule.rule} -> {endpoint} [{', '.join(methods)}]")Solution
Fix 1: Use unique endpoint names with name parameter
from flask import Flask, Blueprint
api_users = Blueprint("api_users", __name__)
admin_users = Blueprint("admin_users", __name__)
@api_users.route("/users")
def get_api_users():
return "API users"
@admin_users.route("/users")
def get_admin_users():
return "Admin users"
app = Flask(__name__)
app.register_blueprint(api_users)
app.register_blueprint(admin_users)Fix 2: Use URL prefixes to separate routes
from flask import Flask, Blueprint
api = Blueprint("api", __name__, url_prefix="/api")
admin = Blueprint("admin", __name__, url_prefix="/admin")
@api.route("/users")
def api_users():
return "API users"
@admin.route("/users")
def admin_users():
return "Admin users"
app = Flask(__name__)
app.register_blueprint(api)
app.register_blueprint(admin)
# /api/users and /admin/users — no conflictFix 3: Use unique function names within blueprints
from flask import Flask, Blueprint
api = Blueprint("api", __name__)
admin = Blueprint("admin", __name__)
@api.route("/users")
def api_get_users():
return "API users"
@admin.route("/users")
def admin_get_users():
return "Admin users"
app = Flask(__name__)
app.register_blueprint(api)
app.register_blueprint(admin)Fix 4: Validate routes at startup
from flask import Flask
def validate_routes(app):
"""Check for duplicate URL rules."""
seen = {}
for rule in app.url_map.iter_rules():
key = (rule.rule, tuple(sorted(rule.methods - {'OPTIONS', 'HEAD'})))
if key in seen:
print(f"CONFLICT: {rule.rule} -> {rule.endpoint} and {seen[key]}")
seen[key] = rule.endpoint
app = Flask(__name__)
# Register all blueprints...
validate_routes(app)Fix 5: Use endpoint parameter to avoid collisions
from flask import Flask, Blueprint
api = Blueprint("api", __name__)
admin = Blueprint("admin", __name__)
@api.route("/users", endpoint="api_users")
def api_users_handler():
return "API users"
@admin.route("/users", endpoint="admin_users")
def admin_users_handler():
return "Admin users"
app = Flask(__name__)
app.register_blueprint(api)
app.register_blueprint(admin)Lessons Learned
- Always give blueprints unique names when creating them — do not rely on the module name.
- Use URL prefixes to separate blueprint routes logically.
- Use unique function names within each blueprint to avoid endpoint collisions.
- Validate your routing table at application startup to catch conflicts early.
- Use the
endpointparameter in@routewhen you need explicit control over endpoint names.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.