Course outline

Svelte / Intermediate: Kit routes and server data policy / Lesson 12

Navigation, URL state and targeted invalidation

Represent shareable view state in URLs and rerun the relevant data contract without assuming a universal cache purge.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain preloading, goto and tracked load dependencies.
  • Keep current page state, invalidation and source freshness distinct.

A shared URL should describe the intended view

Filters, sort order and page cursors often belong in the URL, while temporary focus or an open menu can remain local. A copied client filter that disagrees with the address bar can produce surprising reload and back/forward behavior. Validate path and query input before source access, including repeated parameters. A cursor is a continuation boundary under a data contract, not necessarily a frozen snapshot. Keep private session values out of URLs and logs. Choose whether navigation adds history or replaces it according to the task, and preserve accessible link semantics instead of turning every transition into an opaque click handler.

Target the dependency a load actually declares

The fragment calls invalidate with the same custom dependency label introduced by a server-load example. It is a browser-side Kit navigation API, not a command to purge every external cache. The relevant load must declare or read the dependency under Kitโ€™s tracking rules. A rerun can still return stale data from a source cache, and an unrelated load may not rerun at all. The import and callback were not executed. Use invalidateAll only when its broader current-page behavior is really intended, and review default/custom form-enhancement invalidation separately from manual navigation.

svelte Illustrative targeted load invalidation
<script>
  import { invalidate } from "$app/navigation";
  async function refreshCard() {
    await invalidate("app:course-card");
  }
</script>
<button onclick={refreshCard}>Refresh course card</button>

The matching dependency and browser runtime are prerequisites. No load rerun or cache operation was performed.

Preloading may run work before visible navigation

Link preloading can prepare data before the user commits to a navigation. Keep load functions free of irreversible effects and bound their source cost. goto and link behavior must use approved destinations; an untrusted next parameter can create an open redirect or unsafe URL usage if passed through blindly. Kit may preserve component instances and update data, so do not expect every navigation to rerun initialization. Snapshot or shallow-state features serve particular navigation needs and should not be mistaken for durable storage or server authorization. Verify the selected exact-version behavior rather than assuming all navigation APIs have identical lifetimes.

Define one meaning for repeated filter input

The local parser accepts one state value or a documented default and rejects duplicates. It uses URLSearchParams over synthetic text and makes no request. Another API could allow a list, but every consumer should agree on that shape rather than picking first or last silently. Validation establishes meaning, not permission to see archived courses. A real load should combine the accepted filter with current principal scope and bounded pagination. The test does not exercise Kitโ€™s tracked URL reads, goto history behavior or invalidation; those need a compiled application/browser fixture.

javascript Complete offline URL-filter contract
function stateFilter(query){
  const values=new URLSearchParams(query).getAll("state");
  if(values.length>1)throw new Error("DUPLICATE_STATE");
  const state=values[0]??"published";
  if(!["published","archived"].includes(state))throw new Error("INVALID_STATE");return state;
}
console.assert(stateFilter("")==="published");
console.assert(stateFilter("state=archived")==="archived");
let rejected=false;try{stateFilter("state=published&state=archived");}catch{rejected=true;}console.assert(rejected);

The default and allowed value pass while repetition rejects. No navigation or source policy is tested.

Test current data, retained drafts and identity transitions

Verify direct load, preloaded navigation, back/forward, targeted invalidation and enhanced-form results under the same route/configuration. Check that current data updates while intentional drafts follow their documented reset/reconciliation rule. After account change, discard incompatible pending results and private cached state. A successful invalidate promise does not prove a database write or global freshness. This course runs only the filter parser; it does not execute navigation hooks, preloading, load dependency tracking, history or source caches. Report those limits and use safe synthetic principals for any real authorized integration rather than testing private live accounts.

Common errors and fixes

A refresh reruns nothing relevant

Why it happens
The invalidation target did not match a tracked or declared load dependency.
How to fix it
Align dependency declarations and invalidation vocabulary.
Prevent it next time
Assert the actual load rerun and displayed source revision.

URL and local filter disagree after back navigation

Why it happens
Competing copies of shareable view state had no synchronization contract.
How to fix it
Use validated URL state as the intended source or define explicit reconciliation.
Prevent it next time
Test shared links, reload and history transitions.

Preload performs a write before a click

Why it happens
Rendering/loading contained an irreversible business effect.
How to fix it
Move mutation to an explicit validated authorized server action/endpoint.
Prevent it next time
Test preload separately from confirmed submission.

Check your understanding

1. Does invalidate guarantee every source becomes fresh?

Show worked solution

No. It targets the documented Kit load dependency behavior. An external cache or source can still return old data, and unrelated representations may not rerun. Name the affected layer, verify its revision and separately repair source invalidation when the domain requires it.

2. Why must preloaded load work remain side-effect free?

Show worked solution

The framework may execute it before the user chooses the destination. A mutation there can occur from hover or visibility and repeat independently of explicit intent. Keep loads for deriving permitted data and use a separate mutation contract with current authority and replay handling.

Key takeaways

  • URL state and invalidation need matching explicit contracts.
  • Preloading and preserved components change timing, not domain authority.

Official references