{
  "id": 8662837,
  "title": "FastAPI's new app.frontend() fixes a route-order bug in manual SPA serving",
  "url": "https://urgent.news/2026/09/20/fastapis-new-app-frontend-fixes-a-route-order-bug-in-manual-spa",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-20T10:00:00.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/alexgeorgiev17/fastapis-new-appfrontend-fixes-a-route-order-bug-in-manual-spa-serving-4mm8"
  },
  "original_language": "en",
  "account": "FastAPI introduced a new function, app.frontend(), to improve serving single-page applications (SPAs) that automatically fixes a route-order bug in manual serving. This bug would cause requests to /api/ping returning a 200 response with an HTML instead of JSON body, with no error or 404 indication. The issue occurred because the catch-all route was placed below API routes, and Starlette matched routes based on their declaration order. The new app.frontend() function stores routes separately as _low_priority_routes and checks them only after other path operations fail to match, regardless of where it appears in the file. This ensures that the SPA shell is served correctly even if the route is added later.\n\nAnother problem with the old pattern was that it couldn't distinguish between a client-side navigation and a request for a non-existent asset. Both were treated as unmatched GET requests, resulting in the same response of index.html. FastAPI's new function addresses this by checking the Accept header. If it's set to application/json, it returns a 404, while other requests return the SPA shell. Additionally, the old pattern lacked support for protecting the frontend with authentication and was missing explicit support for HEAD requests, making it less flexible compared to the new approach.",
  "summary": "Put a FastAPI catch-all route above your API route by mistake and a request to /api/ping returns HTTP 200. The body is your single-page app's index.html , not your JSON. No error, no 404, nothing in the logs that looks wrong. I found this while testing app.frontend() , the new call FastAPI shipped across versions 0.138.0 to 0.141.0, between 20 June and 29 July this year. Serving a single-page app…",
  "key_points": [
    "FastAPI introduces app.frontend() to fix route-order bug in SPA serving",
    "app.frontend() separates routes into lowpriorityroutes for correct serving",
    "New function distinguishes between client-side navigation and non-existent assets"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}