2025, Oct 16 00:00

Prefix All Flask Endpoints Under /api Using Blueprint url_prefix (Avoid APPLICATION_ROOT/SCRIPT_NAME 404s)

Learn the correct way to prefix all Flask routes with /api: use blueprint url_prefix or at registration. Avoid 404s caused by APPLICATION_ROOT and SCRIPT_NAME. Clear examples inside.

How to Prefix All Flask Endpoints with /api Without Breaking Your Routes

Putting every endpoint under a common path like /api is a common requirement. It feels natural to reach for configuration keys such as APPLICATION_ROOT or SCRIPT_NAME and expect Flask to prepend the prefix automatically. In practice, this approach leads to 404 when you call /api/... unless you hardcode the prefix in each route or explicitly set it on the blueprint.

The setup that leads to 404

Below is a minimal structure that looks correct at first glance but returns 404 for /api/... because the routes stay at / rather than moving under /api.

# core.py
from flask import Flask

site = Flask(__name__)

# Attempting to mount everything under /api
site.config["SCRIPT_NAME"] = "/api/"
# Alternatively:
# site.config["APPLICATION_ROOT"] = "/api/"
# modules/accounts.py
from flask import Blueprint

acct_bp = Blueprint("accounts_bp", __name__)

@acct_bp.route("/", methods=["GET"])
def fetch_root():
    return "Called get method"

@acct_bp.route("/data", methods=["GET"])
def fetch_data():
    return "Called data method"
# main.py
from core import site
from modules.accounts import acct_bp

site.register_blueprint(acct_bp)

if __name__ == "__main__":
    site.run(debug=True)

Calling /api/ now returns 404. The routes exist, but they are bound to / and /data at the application root, not under /api.

Why this happens

APPLICATION_ROOT and SCRIPT_NAME define the base path where the application is mounted by the WSGI server. They don’t automatically add /api to your routes during development, so @...route("/") ends up at /, not /api/. That mismatch is why requests to /api/... return 404.

Solution: use url_prefix on the blueprint or at registration

The right way to scope a set of routes under a common path is to use url_prefix. You can do this either when creating the blueprint or when registering it. Both achieve the same behavior.

Option A: set the prefix on the blueprint itself.

# core.py
from flask import Flask

site = Flask(__name__)
# modules/accounts.py
from flask import Blueprint

acct_bp = Blueprint("accounts_bp", __name__, url_prefix="/api")

@acct_bp.route("/", methods=["GET"])
def fetch_root():
    return "Called get method"

@acct_bp.route("/data", methods=["GET"])
def fetch_data():
    return "Called data method"
# main.py
from core import site
from modules.accounts import acct_bp

site.register_blueprint(acct_bp)

if __name__ == "__main__":
    site.run(debug=True)
python main.py

>> curl http://127.0.0.1:5000/api/
Called get method
>> curl http://127.0.0.1:5000/api/data
Called data method

Option B: keep the blueprint clean and apply the prefix at registration time.

# core.py
from flask import Flask

site = Flask(__name__)
# modules/accounts.py
from flask import Blueprint

acct_bp = Blueprint("accounts_bp", __name__)

@acct_bp.route("/", methods=["GET"])
def fetch_root():
    return "Called get method"

@acct_bp.route("/data", methods=["GET"])
def fetch_data():
    return "Called data method"
# main.py
from core import site
from modules.accounts import acct_bp

site.register_blueprint(acct_bp, url_prefix="/api")

if __name__ == "__main__":
    site.run(debug=True)
python main.py

>> curl http://127.0.0.1:5000/api/
Called get method
>> curl http://127.0.0.1:5000/api/data
Called data method

Why this is worth knowing

Relying on APPLICATION_ROOT or SCRIPT_NAME to reshape your URL map in development leads to confusing 404s and hides the real source of the problem. Understanding that these keys describe where the app is mounted and do not rewrite routes helps keep your mental model clear. Using url_prefix makes the routing explicit, predictable, and consistent across modules.

Takeaways

If you need every endpoint under /api, prefer url_prefix. Set it either on the blueprint or at registration time, and avoid depending on APPLICATION_ROOT or SCRIPT_NAME for route prefixing during development. This keeps your routing tree transparent and prevents unexpected 404s when you reach for /api/ endpoints.

The article is based on a question from StackOverflow by Mr.Singh and an answer by Ajeet Verma.