Routing is everywhere in frontend, yet many engineers know only one library and one pattern. Senior interviews probe whether you understand the underlying mechanisms (history vs hash), the modern frameworks (Next.js App Router, React Router, TanStack Router), and the architectural tradeoffs.
Hash routing
URL: example.com/#/dashboard
Pros:
- No server config needed (anything after # is client-side)
- Works on static hosts
- Pre-2014 standard
Cons:
- SEO unfriendly (Google ignored hash for years)
- URLs look unprofessional
- No real history API
Modern: avoid except for legacy or very static contexts.
History API routing
URL: example.com/dashboard
The History API (pushState, replaceState, popstate) lets the URL change without a page reload.
history.pushState({ key: 'value' }, '', '/new-path');
window.addEventListener('popstate', handler);
Pros: clean URLs, server can render full HTML for SEO, modern.
Cons: requires server config (all routes serve the SPA shell).
Server config for SPA
For nginx:
location / {
try_files $uri $uri/ /index.html;
}
For Cloudflare Pages, Netlify, Vercel: configured automatically. For Apache: rewrite rules.
React Router
The dominant React routing library. v7+ unifies the SPA and SSR experience.
Patterns:
- Declarative
<Routes>+<Route> - Hooks:
useNavigate,useParams,useSearchParams - Loaders for data fetching
- Actions for mutations
Next.js App Router
The 2024+ paradigm:
- File-system-based routing (app/dashboard/page.tsx)
- Server Components by default
- Route handlers (formerly API routes)
- Server actions for mutations
- Streaming and Suspense built in
TanStack Router
Type-safe routing for React. Newer; growing in popularity. Strong for apps with complex search-param state.
Search params as state
Increasingly recognized: many app states belong in URL query params:
- Filters (?status=active)
- Pagination (?page=2)
- Selected items (?selectedId=123)
Benefit: shareable, browser-back-friendly, indexable.
Library: nuqs for typed query-param management.
Nested routing
Modern apps have layouts that persist across routes:
- App shell at /
- Sidebar at /dashboard/*
- Specific page at /dashboard/profile
React Router and Next.js both support layout nesting elegantly.
Programmatic navigation
const navigate = useNavigate();
navigate('/dashboard');
navigate(-1); // back
navigate({ pathname: '/list', search: '?q=foo' });
Authentication and protected routes
Common pattern:
function ProtectedRoute({ children }) {
const { user } = useAuth();
if (!user) return <Navigate to="/login" />;
return children;
}
Or via loaders that throw redirect on missing auth.
Scroll restoration
By default, navigation does not preserve scroll. Modern routers offer scroll restoration:
- Restore scroll on Back navigation
- Reset to top on forward navigation
React Router has <ScrollRestoration />.
Pre-rendering / static generation
For content sites, pre-render HTML at build time:
- Next.js
generateStaticParams - Astro: static-first by default
- Gatsby: pure static
Common mistakes
- Hash routing in modern apps (legacy unless required)
- No server config for SPA (refresh on /dashboard 404s)
- State in URL params encoded incorrectly
- Browser back not working as users expect
- Heavy navigation (full re-render) instead of partial updates
Frequently Asked Questions
React Router or Next.js App Router?
Next.js App Router for full-stack apps with SSR / SSG needs. React Router for SPA-only apps or non-Next contexts. Both ship in production.
What about Remix?
Remix merged with React Router in 2024 — many of its concepts now in React Router 7. Same primitives.
Should the URL be the source of truth for app state?
For shareable / bookmarkable state: yes. For ephemeral UI state (modal open?): no — local state is fine.