Under The Hood
frontend svelte SvelteKit 2.x

SvelteKit Shallow Routing: pushState & Modal State Sync

Last updated
Prerequisites:
SvelteKit navigation basics
Understanding of the History API
  • sveltekit
  • shallow-routing
  • pushstate
  • modals
  • url
  • navigation

Read at your depth

The practical view

Shallow routing updates the URL without running load functions or triggering a navigation. In SvelteKit: import { pushState } from '$app/navigation'; pushState(url, state);. This changes the address bar and adds a history entry, but does NOT call load, so no data is re-fetched and no component re-renders from the router. Use it for modal/drawer state that you want reflected in the URL (shareable, back-button-closable) without a real page change. To close: pushState back to the original URL, or use the browser's back button (the history entry exists). Read the state via $page.url or $page.state.

The same idea in other frameworks

react equivalent
React Router's history.pushState and URL-search-param state patterns mirror shallow routing.

Legacy vs modern

Full navigation for a modal vs shallow routing

Navigating to a modal URL re-runs load and recreates the page; shallow routing updates only the URL/state, keeping the page and data intact.

before → after
Navigate to a real route for the modal
await goto('/photos/1'); // ❌ OLD: full navigation — load runs, page re-renders
Shallow routing for the modal
pushState(new URL('/photos/1', location.href), { modal: 'photo' }); // ✅ NEW

Interview gotchas

Context

This tests the navigation pipeline distinction — interviewers want you to enumerate what a full navigation triggers (load, component swap) and why shallow routing avoids each for ephemeral UI state.

The mechanical answer

goto (full navigation) runs the navigation pipeline: it resolves the new route, calls its load functions (fetching data), potentially invokes guards, swaps the component tree, and updates the document. pushState bypasses all of that: it only calls history.pushState, updates the $page url/state, and leaves the current component and its data untouched. For a modal, that is exactly right — the overlay is UI state layered on the current page, not a new page. Full navigation would unmount the list, re-fetch data on return, and lose scroll position. Shallow routing also makes the modal's state part of the URL: refresh restores the URL (and you can re-open the modal from it), and the back button naturally closes it because the previous history entry is the closed state.

Trap

The naive answer is 'pushState is just a faster goto'. It does not run load at all — that's a semantic difference, not a speed one. Another trap: expecting the new URL to reflect server state or trigger data updates — it won't, and code that relies on load running will silently keep stale data. Candidates who enumerate the skipped pipeline steps show real understanding.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.