The first time I retrofitted a URL scheme onto an existing web app, it wasn’t easy and the engineers on my team were reluctant. The work itself looked like engineering cleanup, but the problem was design debt: the product had no shared model for what its pages, states, and resources were called.
Routes accumulate around backend data models and frontend file conventions rather than the resource hierarchy a user or linking system would recognize. Ownership fragments across teams; each team names things for its own context. By the time someone wants to clean it up, the redirects are locked in by downstream dependencies and analytics instrumentation is tangled around the old slugs. The retrofix was necessary groundwork for new features that needed stable, meaningful URLs to work at all. The real lesson was that we should have had this conversation at the start, not mid-build.
JSTools.Space explains why that cleanup is so expensive:
A URL is part navigation, part application state, and part public interface. Once users bookmark it, search engines index it, monitoring systems record it, and other applications link to it, changing that URL becomes an architectural decision rather than a cosmetic edit.
Good URL design is therefore less about making every address look pretty and more about making it predictable, stable, and unambiguous.
The decision framework should be a team contract from day one: path for identity, query for optional state, fragment for in-page location or client-only state. Inconsistent routes are what make a migration touch everything. Designers should care because this is information architecture in production, not just routing syntax.

