# State in .svelte.js and .svelte.ts Modules — Svelte / SvelteKit

Source: https://www.skillbyai.com/en/svelte/s-modules

> Runes outside components.

## Universal reactivity

Runes also work in files named `*.svelte.js` or `*.svelte.ts`, so shared reactive logic can live outside components. One rule: you cannot export a `$state` variable that is **reassigned**, because importers would receive a plain value. Instead export an object whose properties you mutate, export getter functions, or use a **class** with `$state` fields. Be careful on the server: module-level state is shared by every request in the same process during SSR, so never store per-user data in a module singleton in a SvelteKit app; use context or load data instead.

## State beyond one component

Svelte offers universal reactive modules, component-tree context and the store contract for sharing state.

![Three ideas: .svelte.ts modules, context, stores.](assets/figures/svelte/section-5-map.svg) — Figure 5.1 — Module state, context per tree and stores.

## A cart class and a shared counter

cart.svelte.ts and its use.

```typescript
// src/lib/cart.svelte.ts
export type Line = { sku: string; name: string; price: number; qty: number };

export class Cart {
  lines = $state<Line[]>([]);
  total = $derived(this.lines.reduce((s, l) => s + l.price * l.qty, 0));

  add(line: Omit<Line, 'qty'>) {
    const existing = this.lines.find((l) => l.sku === line.sku);
    if (existing) existing.qty += 1;
    else this.lines.push({ ...line, qty: 1 });
  }

  remove(sku: string) {
    this.lines = this.lines.filter((l) => l.sku !== sku);
  }
}

// a simple shared object: mutate properties, do not reassign the export
export const ui = $state({ sidebarOpen: false });

// In a component:
//   import { ui } from '$lib/cart.svelte';
//   <button onclick={() => (ui.sidebarOpen = !ui.sidebarOpen)}>Menu</button>
```

## Import without the .ts extension

Import the module as $lib/cart.svelte; the .svelte part of the filename is what lets the compiler process runes in it.

**Quiz:** Why is a module-level $state singleton risky in a SvelteKit app?

- [ ] Runes do not work in modules
- [x] During SSR it is shared by all requests on the server
- [ ] It cannot be imported by components
- [ ] It is reset on every click

*Answer:* During SSR it is shared by all requests on the server. Server modules live as long as the process.
