Skip to content

CORRECT008 · Browser global in server module code

Severity: critical · Category: correctness

Flags reads of browser-only globals (window, document, localStorage, sessionStorage, navigator, location, history, screen, matchMedia, requestAnimationFrame, cancelAnimationFrame, IntersectionObserver, ResizeObserver, MutationObserver, alert, confirm, prompt) in code that always runs on the server:

  • module scope of a .svelte.ts/.svelte.js runes module or a .svelte <script module> block (crashes when the module is imported on the server), and
  • SvelteKit route/hooks files — top level, load/action/endpoint handler bodies, and the init hook (crashes at import or on every request).

Not flagged: code guarded by browser from $app/environment (aliases included) or a typeof window !== 'undefined' check (early-return guards included); code inside onMount/$effect/ordinary functions (they don’t run at module evaluation); a bare typeof window (never throws); names you imported or declared yourself (const document = …); closures nested inside handlers (typically client callbacks); and files that export ssr = false themselves.

None of these globals exist in Node. A module-scope window read crashes the server the moment the file is imported; in a load it crashes every SSR request — ReferenceError: window is not defined, a production 500 the compiler never warns about.

+page.ts
export function load() {
const stored = localStorage.getItem('filters'); // ❌ ReferenceError on the server
return {};
}

Move the browser access to the client side:

+page.svelte
<script>
let stored = $state(null);
$effect(() => {
stored = localStorage.getItem('filters'); // ✅ effects never run on the server
});
</script>

Or guard it explicitly:

import { browser } from '$app/environment';
const stored = browser ? localStorage.getItem('filters') : null; // ✅