Deploy Flutter Web Under a Subpath Without Broken Asset URLs
A Flutter web build hosted below the domain root needs the correct base href. Match the build flag to the final path and test a deep link on the real host.
Root hosting and subpath hosting resolve assets differently
A Flutter web app deployed at https://example.com/ can use the root base path. An app deployed at https://example.com/console/ must resolve its JavaScript, assets, and route URLs beneath /console/. If it was built for /, the page shell may load while asset requests incorrectly go to the domain root.
Build with the deployment path in mind:
flutter build web --release --base-href /console/The trailing slash matters for relative URL resolution. Do not bake a staging path into the release artifact unless the deployment contract requires that exact path.
Test the deployed path, not only the local server
Inspect the generated web/index.html base element and browser network requests. Confirm the hosting server returns the app shell for a route such as /console/settings, and that refresh does not become a server-side 404. A correct base href does not configure the web server's SPA fallback by itself.
Check asset paths, fonts, icons, and API endpoints from the final origin. If the application uses client-side routing, verify a deep link after a fresh browser load, not only after navigating from the home page. Watch for a service worker that still serves an old root-path build.
Keep the environment-specific base path in the release pipeline or build configuration and log it as non-secret metadata. A subpath deployment bug is often a mismatch between artifact and hosting layout, not a Flutter rendering problem, so compare the built artifact with the exact URL prefix before changing application routes.
Treat the base path as part of the artifact contract
The base href tells the browser how to resolve relative resources; it does not rename routes, configure a CDN, or create a server fallback. Keep the expected public URL prefix beside the build command in the deployment configuration. If the same artifact is promoted through staging and production under different prefixes, decide whether the prefix is injected at build time or handled by a deliberate hosting rewrite. Do not let each environment silently patch the generated HTML in a different way, because that makes the deployed artifact difficult to reproduce.
Inspect the final output after the production build. Confirm the <base> element, then load the application directly at the nested path and inspect requests for the main JavaScript bundle, fonts, icons, and assets. A root request can succeed even when every relative asset is being requested from the wrong directory. Use the browser network panel to distinguish a missing asset from an application exception; the HTTP status and requested URL usually reveal the path mismatch immediately.
Test routing and caches at the deployed origin
For a client-side route such as /console/settings, test two flows: navigate to it from the app, and paste the URL into a new browser tab or refresh it. The first uses the client router; the second requires the server or CDN to return the app shell for that path. Configure a scoped fallback for the application prefix so unrelated URLs do not all return the Flutter shell. A broad fallback can mask missing files and make monitoring report false success.
Service workers add another layer. An old worker may keep serving a prior root-path build even after the server contains the corrected output. Test in a clean browser profile and inspect the active worker version. Define how deployments invalidate old caches and ensure that the worker's scope matches the subpath. When diagnosing a suspected cache issue, compare a clean session with the existing profile rather than changing the base href again.
Finally, verify redirects, trailing slashes, and case sensitivity on the real host. Local development servers often hide these differences. Keep the public prefix in a release smoke test so a move from /console/ to /apps/console/ fails visibly before users encounter broken assets or deep links.
Keep a small deployment matrix that lists origin, path prefix, fallback behavior, and cache invalidation for each environment. Have the deployment job compare the expected prefix with the built base element before upload. That check catches a common mistake: reusing a correctly compiled artifact under a different path without rebuilding or intentionally rewriting its base URL.
Test the deployment through a clean browser profile and an existing session. A service worker can continue serving an older root-path build even after the server is corrected. Include a version marker in the app shell and define how the worker is updated or retired. This makes a path incident observable and prevents a developer from changing the base href again when the real problem is stale client-side cache state.