Darren Xu Blog

Hash routing breaks stuff


Hash routing is a client-side routing technique that uses the URL fragment (#...) to represent view state without reloading the page. It is extremely common in older SPAs, but the pattern has a lot of hidden costs.

Everything after the # is technically a fragment identifier.

Why people reach for it

Those are valid reasons for legacy apps, but they don’t make it the right choice for modern web architecture.

Why hash routing is bad

A URL is a contract. Once you start using # as a routing mechanism, it becomes harder to reason about what that URL actually means.

What fragments should be used for

Fragments are ideal for document-level navigation:

If the browser can do this for you natively, don’t replace it with a state-management hack.

What to use instead

Use the History API / real URLs

Modern client-side routing should use normal paths and query params instead of fragments. That keeps URLs meaningful, shareable, and indexable.

Keep state out of the URL when it doesn’t belong there

If you are only storing ephemeral UI state, consider local state, context, or a store. The URL should describe the page, not every toggle and filter value.

Preserve native navigation semantics

If you need an anchor destination, use a normal #target link. If you need to represent a page or view, use a path like /users/123 or /settings/profile.

Practical guidance