Svelte has the highest developer satisfaction score of any frontend framework — 62.4% admired rating in the Stack Overflow 2025 Developer Survey of 49,000+ developers, outranking React at 52.1%, Vue at 50.9%, and Angular at 44.7%. Svelte has earned this position through a fundamentally different architecture: it is a compiler, not a runtime framework. Where React ships 45KB+ of runtime JavaScript to every user's browser and Vue ships 35KB+, Svelte compiles your component code into vanilla JavaScript at build time — producing zero framework code in the browser output. The result is bundle sizes 30–40% smaller than React equivalents, startup times 2–3x faster in 2025 benchmarks, and direct DOM updates without virtual DOM diffing overhead. Svelte 5 — released in late 2024 — rewrote the reactivity system from scratch with Runes: a set of compiler-understood functions ($state, $derived, $effect, $props, $bindable) that replace the old implicit reactivity model with explicit, fine-grained reactive primitives that scale to complex applications. SvelteKit 2.0 is the official full-stack meta-framework — file-based routing, SSR, SSG, server endpoints, edge deployment, and progressive form enhancement — giving developers the equivalent of React plus Next.js in one coherent package. Companies including The New York Times, Spotify, Netflix, Apple (Podcasts web app, 2024), AutoTrader UK, and Square Enix use Svelte in production. This guide covers everything from first principles to production patterns in 2026.
Svelte in 2026: Adoption, Statistics, and Why It Matters
Svelte's position in the frontend landscape in 2026 is best described as the most admired small-ecosystem framework — high satisfaction, strong performance advantages, and growing enterprise adoption, in a market still dominated by React's network effects and talent pool. The data from 2025 surveys tells a precise story.
| Metric | Data Point | Source |
|---|---|---|
| Developer satisfaction (admired) | 62.4% — highest of any frontend framework, above React (52.1%), Vue (50.9%), Angular (44.7%) | Stack Overflow Developer Survey 2025 (49,000+ respondents) |
| Developer usage (popularity) | 7.2% of all developers — 5th place behind React (44.7%), Angular (18.2%), Vue (17.6%) | Stack Overflow Developer Survey 2025 |
| Desired framework | 11.1% of developers want to learn Svelte — above Angular (12.6%) and closing quickly | Stack Overflow Developer Survey 2025 |
| State of JS survey growth | Usage grew from 8% to 20% in two years — fastest growth trajectory of major frameworks | State of JS 2023 survey |
| GitHub stars | 80,000+ by mid-2025 — up from 32,000 in 2019 (150% growth in 6 years) | GitHub / TFC analysis 2025–2026 |
| npm weekly downloads | 1.7 million per week (March 2025) — 4th behind React (30M+), Vue, Angular | InfoWorld / npm trends March 2025 |
| Bundle size advantage | 30–40% smaller bundles than React equivalents — zero runtime in browser output | Strapi comparison 2025; multiple benchmarks |
| Startup time benchmark | Svelte 5 apps startup 2–3x faster than React equivalents | JavaScript Doctor blog / benchmarks 2025 |
| Code volume reduction | 40% less code than equivalent React implementations — no hooks, no JSX boilerplate | Strapi / multiple 2025 comparisons |
| Searches for 'Svelte vs React 2025' | 60% increase year-over-year — growing developer awareness | JavaScript Doctor blog 2025 |
| Satisfaction score (relative) | Svelte 5.3 vs React 2.9 vs Angular 0.7 on satisfaction index | Framework comparison aggregated data 2024 |
| Production deployments | New York Times, Spotify, Netflix, Apple Podcasts (2024), AutoTrader UK, Square Enix | TFC analysis October 2025 |
What Is Svelte
Svelte is a component-based frontend framework for building user interfaces that takes a fundamentally different approach from every other major framework: it is a compiler rather than a runtime library. You write Svelte components in .svelte files — single-file components that combine HTML, JavaScript, and CSS in one place. At build time, the Svelte compiler transforms these .svelte files into highly optimized vanilla JavaScript that manipulates the DOM directly. The compiled output contains no Svelte framework code — it is pure, tight JavaScript that any browser can run without downloading a framework runtime. This is the defining characteristic that separates Svelte from React, Vue, and Angular: those frameworks ship their runtime (the code that manages the virtual DOM, state reconciliation, and component lifecycle) to every user's browser on every page load. Svelte's runtime is zero — it was consumed at build time and its output is the equivalent of hand-optimized vanilla JavaScript. Svelte was created by Rich Harris, a graphics editor and journalist at The Guardian who needed a tool to build fast, lightweight interactive graphics for news stories. The first release was in 2016. Svelte 3 (2019) introduced a component model that felt like writing vanilla HTML and JavaScript. Svelte 4 (2023) improved tooling and TypeScript support. Svelte 5 (late 2024) rewrote the reactivity system with Runes — the most significant update since the framework's creation.
Why Svelte Was Created: The Problem with Virtual DOM
Rich Harris created Svelte while building interactive data visualizations at The Guardian, where performance on low-end devices and slow networks was a real constraint, not an abstract concern. The problem he identified was that frameworks like React and Angular added significant overhead to solve a problem — efficient DOM updates — that a compiler could solve at build time instead of at runtime. The virtual DOM model that React popularized works as follows: when state changes, React re-renders the component to a virtual DOM tree (an in-memory JavaScript object), then diffs the new virtual DOM against the previous one, and finally applies the minimal set of real DOM mutations that brings the actual DOM into alignment. This process happens in the browser, on the user's device, on every state change. It requires shipping the virtual DOM engine, the reconciler, and the component runtime to every user. Rich Harris argued in his influential 2019 post 'Virtual DOM is pure overhead' that the virtual DOM was not a performance feature — it was a necessary cost of the React programming model, and a cost that should be paid once at build time rather than on every user's device on every render. Svelte's compiler reads your component code, understands which parts of the DOM depend on which reactive variables, and generates JavaScript that updates exactly those DOM nodes when those variables change. No diffing. No virtual DOM. No runtime reconciliation. The browser runs the minimum possible code to keep the UI current. The average JavaScript app in 2025 ships 1.7MB of framework code before a single line of business logic. Svelte's compiled output is a fraction of this — which matters most for mobile users on slow connections and low-end devices.
How Svelte Works: The Compiler Model
Understanding Svelte's compilation model — what happens at build time and what runs in the browser — is essential for reasoning about performance, debugging, and the limits of what Svelte can and cannot do. The compilation pipeline has three stages. Stage 1 — Parsing: The Svelte compiler reads your .svelte file and separates the three sections: the script block (JavaScript or TypeScript), the template (HTML with Svelte template syntax), and the style block (CSS). It parses each section into an AST and analyzes the relationships between reactive variables in the script and the template nodes that use them. Stage 2 — Analysis: The compiler identifies which template nodes depend on which reactive state. For a component that has a reactive variable count displayed in a div, the compiler knows at build time that this div — and only this div — needs to update when count changes. This analysis is what makes Svelte's updates so precise: no runtime diffing is needed because the compiler has already mapped every reactive dependency at build time. Stage 3 — Code Generation: The compiler outputs a JavaScript module that creates the DOM nodes imperatively on mount, sets up the minimal event listeners needed, and generates update functions for each reactive dependency that directly mutate only the specific DOM nodes affected by each variable. The output is verbose but fast — it is essentially the hand-optimized vanilla JavaScript that an expert developer would write for a trivial component, generated automatically for components of any complexity. Scoped CSS is also transformed: the compiler adds a unique hash attribute to every element in the component and transforms the CSS selectors to match only those elements — achieving component-level CSS isolation without any runtime CSS-in-JS overhead.
Svelte vs React vs Vue: Full Comparison
The choice between Svelte, React, and Vue is the most common framework decision developers face in 2026. The comparison is genuinely nuanced — each framework has real advantages for specific use cases, team sizes, and project requirements.
| Dimension | Svelte | React | Vue |
|---|---|---|---|
| Architecture | Compiler — framework consumed at build time. Zero runtime in browser output. DOM updated via compiled vanilla JS. | Runtime library — 45KB+ runtime in every browser load. Virtual DOM diffing on every state change. | Runtime framework — 35KB+ runtime. Virtual DOM diffing. Options API and Composition API both available. |
| Bundle size | Smallest — 30–40% smaller than React equivalents. No framework runtime in output. | Largest of the three — React + ReactDOM runtime (~45KB gzipped) is baseline overhead before app code. | Middle — Vue 3 runtime (~23KB gzipped) is smaller than React but larger than Svelte compiled output. |
| Startup time | 2–3x faster than React in 2025 benchmarks — direct DOM manipulation from compiled output | Slower initial startup due to React runtime initialization and virtual DOM creation | Faster than React, slower than Svelte — good balance for most applications |
| Developer satisfaction | 62.4% admired — highest of any framework (Stack Overflow 2025) | 52.1% admired — 2nd place | 50.9% admired — 3rd place |
| Usage/popularity | 7.2% of developers — 5th place | 44.7% — dominant leader | 17.6% — 3rd place |
| Learning curve | Lowest — minimal boilerplate, no hooks, no JSX required, component structure is closest to vanilla HTML | Medium — hooks rules, JSX syntax, React mental model for state and effects | Low-medium — Options API is approachable; Composition API requires more understanding |
| Job market | Small but growing — 900 Svelte positions vs 110,000+ React on LinkedIn (122:1 ratio) | Dominant — 52% of frontend job listings mention React | Good — used widely in Asia, growing in Europe |
| Ecosystem | Younger and smaller — SvelteKit (official), limited third-party UI libraries compared to React | Largest — React Router, Redux, Zustand, React Query, thousands of component libraries (Material UI, Ant Design, Chakra) | Large — Vue Router, Pinia, Vuetify, Nuxt.js — stronger in Asia and Europe |
| State management | Built-in stores (writable, readable, derived) — no external library needed for most use cases | External libraries required — Context API covers simple cases; Redux, Zustand, MobX for complex state | Pinia (official) or Vuex — official solutions included in the ecosystem |
| TypeScript support | Full — Svelte 5 significantly improved TypeScript integration; SvelteKit defaults to TypeScript | Excellent — TypeScript is mainstream in React ecosystem | Excellent — Vue 3 was rewritten in TypeScript; full type support |
| SSR / full-stack | SvelteKit 2.0 — file-based routing, SSR, SSG, server endpoints, edge deployment, progressive forms | Next.js — mature, widely used, React Server Components, large ecosystem | Nuxt.js — mature, widely used, similar to Next.js feature set |
| Best for | Performance-critical apps, mobile-first apps, news/media interactive graphics, startups optimizing for load time, developers who want minimal boilerplate | Large teams, enterprise projects, React Native mobile, projects requiring maximum ecosystem coverage and hiring ease | Small-medium teams, Asian market products, teams wanting a balance of approachability and power |
Installing Svelte and SvelteKit
SvelteKit is the official full-stack meta-framework for Svelte — it handles routing, SSR, SSG, server endpoints, and deployment adapters. For any project beyond a simple static page, SvelteKit is the correct starting point. Installing SvelteKit installs Svelte automatically.
# Create a new SvelteKit project (includes Svelte 5)
npm create svelte@latest my-app
# The CLI prompts you to choose:
# - Skeleton project (minimal) or Demo app
# - TypeScript / JavaScript / JSDoc type checking
# - ESLint, Prettier, Playwright (e2e testing), Vitest (unit testing)
cd my-app
npm install
# Start development server — Vite powers HMR (Hot Module Replacement)
npm run dev
# App runs at http://localhost:5173 by default
# Build for production
npm run build
# Preview the production build locally
npm run preview
# For a standalone Svelte project without SvelteKit (rare — most projects use SvelteKit)
# npm create vite@latest my-svelte-app -- --template svelte-ts
# Svelte REPL — no installation needed, browser-based playground
# https://svelte.dev/repl — ideal for learning and quick experiments
# SvelteKit deployment adapters — install before building for specific platforms
npm install -D @sveltejs/adapter-vercel # Vercel
npm install -D @sveltejs/adapter-netlify # Netlify
npm install -D @sveltejs/adapter-cloudflare # Cloudflare Pages/Workers
npm install -D @sveltejs/adapter-node # Self-hosted Node.js server
# adapter-auto (default) detects the deployment platform automaticallySvelte Component Structure
A Svelte component is a .svelte file with up to three sections: a script block for JavaScript or TypeScript logic, a template section for HTML markup with Svelte expressions, and an optional style block for scoped CSS. All three sections are optional — a valid .svelte file can contain just HTML. The three sections can appear in any order, though the conventional order is script, then template, then style.
<!-- UserCard.svelte — a complete Svelte component -->
<script lang="ts">
// 'lang="ts"' enables TypeScript — remove for JavaScript
// In Svelte 5, props use the $props() rune (covered in next section)
// This example shows Svelte 5 syntax
let { name, role = "Member", avatarUrl }: {
name: string;
role?: string;
avatarUrl?: string;
} = $props();
// Local reactive state
let isExpanded = $state(false);
function toggleExpand() {
isExpanded = !isExpanded;
}
</script>
<!-- Template: HTML with Svelte expressions in {} -->
<div class="card" class:expanded={isExpanded}>
{#if avatarUrl}
<img src={avatarUrl} alt="{name}'s avatar" />
{/if}
<div class="info">
<h2>{name}</h2>
<span class="role">{role}</span>
</div>
<button onclick={toggleExpand}>
{isExpanded ? 'Show Less' : 'Show More'}
</button>
{#if isExpanded}
<div class="details">
<p>Expanded details for {name}</p>
</div>
{/if}
</div>
<!-- Scoped styles — selectors only match elements in THIS component -->
<!-- Svelte adds a unique hash attribute to achieve isolation -->
<style>
.card {
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 1rem;
max-width: 320px;
}
.card.expanded {
border-color: #6366f1;
}
h2 {
/* This h2 style ONLY affects h2 elements inside this component */
/* It will NOT affect h2 elements in parent or child components */
margin: 0;
font-size: 1.125rem;
}
.role {
color: #64748b;
font-size: 0.875rem;
}
</style>Svelte 5 Runes: The New Reactivity System
Svelte 5's Runes are the most significant change since the framework's creation. Released in late 2024, Runes replace Svelte 4's implicit reactivity model (where any top-level let variable was automatically reactive) with explicit reactive primitives that are compiler-understood functions prefixed with $. Runes solve the scaling problems of Svelte 4 reactivity, provide consistent behavior inside and outside components, and integrate fully with TypeScript's type system. Svelte 4 code continues to work in Svelte 5 — the migration is optional and incremental.
<script lang="ts">
// ===== $state — reactive state =====
// Equivalent to React's useState, but no destructuring required
let count = $state(0);
let user = $state({ name: "Priya", age: 28 });
// Mutate object properties directly — Svelte 5 tracks deep reactivity
function birthday() {
user.age += 1; // this correctly triggers a re-render in Svelte 5
// In Svelte 4: reassigning the whole object was required for objects
}
// ===== $derived — computed state =====
// Equivalent to React's useMemo, Vue's computed
// Re-evaluates automatically when dependencies change
let doubled = $derived(count * 2);
let greeting = $derived(`Hello, ${user.name}!`);
// $derived.by for multi-line derived logic
let summary = $derived.by(() => {
if (count === 0) return "No items";
if (count === 1) return "One item";
return `${count} items`;
});
// ===== $effect — side effects =====
// Equivalent to React's useEffect — runs after DOM updates
// Automatically re-runs when reactive dependencies used inside change
$effect(() => {
console.log("count changed to:", count);
document.title = `Count: ${count}`;
// Return a cleanup function (optional)
return () => {
console.log("cleanup before next effect or unmount");
};
});
// ===== $props — component props =====
// Replaces Svelte 4's export let syntax
let { title, description = "No description" }: {
title: string;
description?: string;
} = $props();
// ===== $bindable — two-way bindable props =====
// Allows parent to bind to this prop with bind:propName
let { value = $bindable("") } = $props();
</script>
<button onclick={() => count++}>Count: {count}</button>
<p>Doubled: {doubled}</p>
<p>Summary: {summary}</p>Reactivity in Svelte 4 vs Svelte 5
Understanding the differences between Svelte 4 and Svelte 5 reactivity is important because most existing tutorials, blog posts, and Stack Overflow answers as of early 2026 are written for Svelte 4 — and some patterns from Svelte 4 behave differently or are replaced in Svelte 5.
| Feature | Svelte 4 Syntax | Svelte 5 Runes Syntax | Key Difference |
|---|---|---|---|
| Reactive state | let count = 0; (any top-level let is reactive) | let count = $state(0); | Svelte 5 requires explicit $state declaration. Svelte 4 implicit reactivity is not available inside .svelte.ts files or shared modules — Runes work everywhere. |
| Reactive declarations (computed) | $: doubled = count * 2; (reactive label syntax) | let doubled = $derived(count * 2); | Svelte 4's $: label applies to any statement, making it ambiguous between re-execution and derived values. $derived is explicit about producing a value. |
| Side effects | $: { console.log(count); } (reactive label with block) | $effect(() => { console.log(count); }); | $effect is explicit, supports cleanup return values, and has clearer semantics for async effects. |
| Component props | export let title; export let count = 0; | let { title, count = 0 } = $props(); | Svelte 5 props use destructuring from $props() — type inference with TypeScript is much cleaner. Svelte 4 used module-style exports. |
| Object mutation | user = { ...user, age: 29 } (required reassignment) | user.age = 29; (direct mutation works) | Svelte 5 tracks deep reactive state — property mutations trigger updates. Svelte 4 only tracked top-level variable reassignment. |
| Two-way binding in props | export let value; (parent uses bind:value) | let { value = $bindable('') } = $props(); | $bindable is explicit — it documents which props support two-way binding. In Svelte 4, all exported props implicitly supported binding. |
| Stores (global state) | import { writable } from 'svelte/store'; $store shorthand syntax | Stores still work in Svelte 5 — and $state can now be used in shared modules outside components | Svelte 5 Runes can be used in .svelte.ts files, reducing the need for stores for shared state. |
Handling Events
Svelte 5 changed event handling from the on:eventname directive to standard JavaScript onclick, oninput, and other lowercase event properties. This aligns Svelte's event syntax with the web platform's standard event attribute names and makes Svelte easier to learn for developers coming from vanilla JavaScript.
<script lang="ts">
let inputValue = $state("");
let clickCount = $state(0);
// Inline handlers — for simple one-liners
// Svelte 5: onclick={} (not on:click={})
// Svelte 4: on:click={} — still works but deprecated in Svelte 5
function handleSubmit(event: SubmitEvent) {
event.preventDefault();
console.log("Submitted:", inputValue);
}
function handleKeydown(event: KeyboardEvent) {
if (event.key === "Enter") {
console.log("Enter pressed");
}
}
</script>
<!-- Svelte 5 event syntax — standard DOM event names, no on: prefix -->
<button onclick={() => clickCount++}>
Clicked {clickCount} times
</button>
<!-- Passing event object -->
<button onclick={(e) => console.log(e.target)}>
Log target
</button>
<!-- Named handler function -->
<form onsubmit={handleSubmit}>
<input
type="text"
value={inputValue}
oninput={(e) => inputValue = e.currentTarget.value}
onkeydown={handleKeydown}
/>
<button type="submit">Submit</button>
</form>
<!-- Two-way binding with bind: — shortcut for value + oninput pattern -->
<input bind:value={inputValue} placeholder="Bound input" />
<!-- bind:value automatically handles both reading and updating inputValue -->
<!-- bind: works for many HTML attributes -->
<input type="checkbox" bind:checked={isActive} />
<select bind:value={selectedOption}>
<option value="a">Option A</option>
<option value="b">Option B</option>
</select>Props and Parent-Child Communication
In Svelte 5, props flow from parent to child using $props() in the child component, and from child to parent using either callback props (functions passed as props) or $bindable() for two-way binding. This is the same unidirectional data flow model used by React — data flows down via props, events flow up via callbacks.
<!-- ===== Child component: Counter.svelte ===== -->
<script lang="ts">
// $props() receives all props passed from the parent
let {
initialCount = 0, // optional prop with default
label = "Count", // optional prop with default
onCountChange, // callback prop — function from parent
}: {
initialCount?: number;
label?: string;
onCountChange?: (newCount: number) => void;
} = $props();
let count = $state(initialCount);
function increment() {
count++;
onCountChange?.(count); // call parent callback if provided
}
function decrement() {
count--;
onCountChange?.(count);
}
</script>
<div class="counter">
<span>{label}: {count}</span>
<button onclick={decrement}>−</button>
<button onclick={increment}>+</button>
</div>
<!-- ===== Parent component: App.svelte ===== -->
<script lang="ts">
import Counter from "./Counter.svelte";
let totalCount = $state(0);
function handleCountChange(newCount: number) {
console.log("Counter changed to:", newCount);
totalCount = newCount;
}
</script>
<!-- Passing props to child — same syntax as HTML attributes -->
<Counter
initialCount={5}
label="Items"
onCountChange={handleCountChange}
/>
<p>Parent sees: {totalCount}</p>
<!-- ===== Slot / snippet for content projection ===== -->
<!-- Svelte 5 replaces <slot> with snippets -->
<!-- Child: Card.svelte -->
<!-- {#snippet header()}<slot name="header" />{/snippet} -->
<!-- Parent uses: {#snippet header()}<h2>Title</h2>{/snippet} -->Svelte Stores: Global State Management
Svelte stores provide reactive state that lives outside components — accessible from anywhere in your application without prop drilling. Svelte ships three built-in store types: writable (read and write), readable (read-only, controlled externally), and derived (computed from other stores). Svelte 5 adds the ability to use $state in shared .svelte.ts modules, which reduces the need for stores for simple shared state.
// stores/auth.ts — a writable store
import { writable, derived, get } from "svelte/store";
// writable(initialValue) — can be read and written from anywhere
export const user = writable<{
name: string;
email: string;
role: "admin" | "user";
} | null>(null);
// Derived store — computed from another store
// Automatically updates when user store changes
export const isAdmin = derived(
user,
($user) => $user?.role === "admin" ?? false
);
export const displayName = derived(
user,
($user) => $user?.name ?? "Anonymous"
);
// Store methods — encapsulate logic alongside the store
export const auth = {
login(userData: { name: string; email: string; role: "admin" | "user" }) {
user.set(userData);
},
logout() {
user.set(null);
},
// get() reads store value outside Svelte component context
isLoggedIn: () => get(user) !== null,
};
// ===== Using stores in a component =====
// Component: Header.svelte
/*
<script lang="ts">
import { user, isAdmin, auth } from "../stores/auth.ts";
// In Svelte components, prefix store with $ to auto-subscribe
// $user — automatically subscribes and unsubscribes on component lifecycle
// No manual subscribe/unsubscribe management needed
</script>
{#if $user}
<span>Welcome, {$user.name}</span>
{#if $isAdmin}
<a href="/admin">Admin Panel</a>
{/if}
<button onclick={auth.logout}>Logout</button>
{:else}
<a href="/login">Login</a>
{/if}
*/
// ===== Svelte 5 alternative: $state in shared module =====
// For Svelte 5 projects, simple shared state can use $state in .svelte.ts files
// auth.svelte.ts
export const authState = $state({
user: null as { name: string } | null,
isLoading: false,
});
// Import and use directly in components — no $ prefix needed for object stateLifecycle Functions
Svelte provides lifecycle functions for running code at specific points in a component's lifecycle. In Svelte 5, the $effect rune largely replaces the need for onMount and beforeUpdate in many use cases, but the explicit lifecycle functions remain available and useful for specific patterns.
<script lang="ts">
import { onMount, onDestroy, beforeUpdate, afterUpdate, tick } from "svelte";
// onMount — runs once when the component is added to the DOM
// Correct place for: API calls, third-party library initialization,
// DOM measurements, starting intervals
onMount(() => {
console.log("Component mounted — DOM is ready");
const interval = setInterval(() => {
// update something every second
}, 1000);
// Return a cleanup function — called on component destroy
return () => clearInterval(interval);
});
// onDestroy — runs when the component is removed from the DOM
// Use for cleanup not handled by onMount return value
onDestroy(() => {
console.log("Component destroyed");
});
// beforeUpdate — runs before the DOM is updated
// Useful for capturing scroll position before a re-render
let listElement: HTMLElement;
let scrollPosition = 0;
beforeUpdate(() => {
if (listElement) {
scrollPosition = listElement.scrollTop;
}
});
// afterUpdate — runs after the DOM is updated
// Useful for restoring scroll position or measuring updated DOM
afterUpdate(() => {
if (listElement) {
listElement.scrollTop = scrollPosition;
}
});
// tick — returns a promise that resolves after the next DOM update
// Use when you need to read the DOM after a state change
let count = $state(0);
async function incrementAndMeasure() {
count++;
await tick(); // wait for DOM to update with new count
const element = document.getElementById("counter");
console.log("Element height after update:", element?.offsetHeight);
}
// In Svelte 5 — $effect replaces many onMount + afterUpdate patterns
$effect(() => {
// Equivalent to onMount for most initialization use cases
// Runs after mount AND after every reactive update that changes dependencies
console.log("count is now:", count);
});
</script>Svelte Built-In Transitions and Animations
Svelte's built-in transition and animation system is one of its most distinctive features — zero-dependency, declarative animations powered by the compiler. Where React requires Framer Motion or react-spring (adding 50–170KB to bundle size), Svelte's transitions are compiler-aware and add only the code needed for the transitions you actually use.
<script lang="ts">
import { fade, fly, slide, scale, blur, draw } from "svelte/transition";
import { flip } from "svelte/animate";
import { tweened, spring } from "svelte/motion";
import { cubicOut } from "svelte/easing";
let visible = $state(true);
let items = $state(["Mango", "Papaya", "Guava", "Banana"]);
// tweened — smooth animation to a target value
const progress = tweened(0, { duration: 400, easing: cubicOut });
function loadProgress() {
progress.set(100); // animates from current value to 100
}
// spring — physics-based animation (overshoots and settles)
const coords = spring({ x: 50, y: 50 }, { stiffness: 0.1, damping: 0.25 });
</script>
<!-- in: transition runs when element enters the DOM -->
<!-- out: transition runs when element leaves the DOM -->
<!-- transition: runs both in and out with the same transition -->
<button onclick={() => visible = !visible}>Toggle</button>
{#if visible}
<!-- fade: opacity 0 → 1 on enter, 1 → 0 on exit -->
<div transition:fade={{ duration: 300 }}>Fade me</div>
<!-- fly: moves in from offset position -->
<p in:fly={{ y: 50, duration: 400 }} out:fade={{ duration: 200 }}>
Fly in, fade out
</p>
<!-- slide: height animation (accordion effect) -->
<div transition:slide={{ duration: 200 }}>
Slide open and close
</div>
{/if}
<!-- Progress bar using tweened motion store -->
<button onclick={loadProgress}>Load</button>
<progress value={$progress} max="100"></progress>
<!-- Animated list with flip — smooth reordering animation -->
<!-- flip animates items to their new position when list order changes -->
{#each items as item (item)}
<div animate:flip={{ duration: 300 }}>
{item}
</div>
{/each}
<!-- Custom transition — any CSS animation can be expressed as a transition function -->
<!-- transition:customTransition — receives node and params, returns { duration, css } -->SvelteKit: Full-Stack Applications with Svelte
SvelteKit is to Svelte what Next.js is to React — the official full-stack meta-framework that adds routing, server-side rendering, static site generation, server endpoints, form actions, and deployment adapters. For any application that needs more than a client-side SPA, SvelteKit is the correct starting point. SvelteKit 2.0 introduced Svelte 5 support, improved routing types, and enhanced edge deployment capabilities.
| SvelteKit Feature | How It Works | Equivalent in Next.js |
|---|---|---|
| File-based routing | Files in src/routes/ map to URLs. src/routes/about/+page.svelte is the /about page. src/routes/blog/[slug]/+page.svelte is a dynamic /blog/:slug route. | app/ or pages/ directory routing in Next.js |
| Page data loading | +page.ts exports a load function that runs on the server for SSR or at build time for SSG. Returns data available as props.data in the page component. | getServerSideProps or getStaticProps in Pages Router; async Server Components in App Router |
| Server endpoints | +server.ts files in the routes directory export GET, POST, PUT, DELETE handlers — REST API routes that run server-side only. | route.ts files in Next.js App Router; pages/api/ in Pages Router |
| Form actions | +page.server.ts exports actions — server-side form handlers. SvelteKit forms work without JavaScript (progressive enhancement) and with JavaScript for enhanced UX. | Server Actions in Next.js 13+ |
| Layout components | +layout.svelte files wrap all child routes. src/routes/+layout.svelte wraps the entire app. Nested layouts are supported. | layout.tsx in Next.js App Router |
| SSR vs SSG control | export const prerender = true in +page.ts for static generation. export const ssr = false for client-side only. Default is SSR. | generateStaticParams for SSG; no generateStaticParams for SSR in App Router |
| Deployment adapters | adapter-vercel, adapter-netlify, adapter-cloudflare, adapter-node — swap adapters to deploy to different platforms with no code changes. | Next.js is primarily optimized for Vercel; other platforms require configuration |
| Environment variables | $env/static/private for server-side secrets (never exposed to client), $env/static/public for client-safe values — typed and imported as modules. | process.env for server; NEXT_PUBLIC_ prefix for client exposure |
// src/routes/blog/[slug]/+page.ts — server data loader
import type { PageLoad } from "./$types";
export const load: PageLoad = async ({ params, fetch }) => {
// This runs on the server for SSR, or at build time for SSG
const response = await fetch(`/api/posts/${params.slug}`);
if (!response.ok) {
// SvelteKit's error() function returns a proper HTTP error response
throw error(404, "Post not found");
}
const post = await response.json();
return {
post, // available as data.post in the page component
slug: params.slug,
};
};
// src/routes/blog/[slug]/+page.svelte — the page component
// <script lang="ts">
// import type { PageData } from "./$types";
// let { data }: { data: PageData } = $props();
// </script>
// <h1>{data.post.title}</h1>
// <article>{@html data.post.content}</article>TypeScript in Svelte
TypeScript support in Svelte 5 is significantly improved over Svelte 4 — particularly for $props() type inference and component type checking. Add lang="ts" to the script block to enable TypeScript in a .svelte file. SvelteKit generates typed route utilities in ./$types that provide full type safety for load functions, page data, and action parameters.
<!-- Profile.svelte — TypeScript in a Svelte 5 component -->
<script lang="ts">
// Define prop types directly in the $props() destructuring
let {
userId,
showEmail = false,
onSave,
}: {
userId: number;
showEmail?: boolean;
onSave: (data: { name: string }) => Promise<void>;
} = $props();
// Typed reactive state
interface UserProfile {
id: number;
name: string;
email: string;
bio?: string;
}
let profile = $state<UserProfile | null>(null);
let isLoading = $state(true);
let error = $state<string | null>(null);
// Typed lifecycle with async fetch
onMount(async () => {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error("Failed to load");
profile = await response.json() as UserProfile;
} catch (e) {
error = e instanceof Error ? e.message : "Unknown error";
} finally {
isLoading = false;
}
});
// Typed event handler
function handleNameInput(event: Event & { currentTarget: HTMLInputElement }) {
if (profile) {
profile.name = event.currentTarget.value;
}
}
// Typed derived state
let displayName = $derived(
profile?.name ?? "Loading..."
);
</script>
{#if isLoading}
<p>Loading...</p>
{:else if error}
<p>Error: {error}</p>
{:else if profile}
<div>
<h2>{displayName}</h2>
{#if showEmail}
<p>{profile.email}</p>
{/if}
</div>
{/if}Common Mistakes and How to Avoid Them
The following mistakes account for the majority of frustrations reported by developers new to Svelte — particularly those transitioning from React backgrounds.
AI Assisted Web DevelopmentWeb Developer RoadMap
- Using React patterns in Svelte — the most common mistake for React developers. In Svelte, you do not call a setter function to update state (no setCount(count + 1)). You reassign the variable (count++ or count = count + 1). There are no hooks rules — $state, $derived, and $effect can be called conditionally and in loops. There is no JSX — Svelte uses HTML template syntax with {expressions} and directives like {#if}, {#each}, and {#await}. Trying to apply React's mental model to Svelte produces confusing results because the underlying execution model is completely different.
- Not understanding the difference between Svelte 4 and Svelte 5 syntax — as of early 2026, most tutorials, Stack Overflow answers, and blog posts are written for Svelte 4 (export let for props, $: for reactivity, on:click for events). Svelte 5 uses $props(), $state, $derived, $effect, and onclick. The frameworks are mostly compatible but the syntax differs enough to cause confusion. Always check the date and Svelte version of any tutorial you follow. New projects should use Svelte 5 syntax.
- Misusing stores for simple local state — Svelte stores are for state that needs to be shared between multiple unrelated components. For state that belongs to a single component or passes through a clear component hierarchy, use $state in the component directly and pass via props. Using a writable store for every piece of state is the Svelte equivalent of putting everything in Redux — unnecessary complexity that slows down code without providing benefits.
- Forgetting that Svelte's CSS is scoped by default — styles in a .svelte file's style block only apply to elements in that component. A .card selector in a parent component will not style a .card element in a child component. This is intentional and prevents cascading style conflicts, but it surprises developers used to global CSS. To style child component elements from a parent, use :global(.selector) or pass CSS custom properties (CSS variables) as props.
- Incorrect object mutation in Svelte 4 — Svelte 4 only tracks top-level variable reassignment for reactivity. Mutating an object property (user.name = 'Alice') does NOT trigger a UI update in Svelte 4 — you must reassign the variable (user = { ...user, name: 'Alice' }). Svelte 5 with $state() resolves this — deep property mutations are tracked. This is one of the most common bugs when following Svelte 4 tutorials.
- Using stores as a SvelteKit data fetching solution — SvelteKit's load functions (+page.ts) and server routes (+server.ts) are the correct mechanism for fetching data in SvelteKit applications. Using a writable store in onMount to fetch API data bypasses SvelteKit's SSR, caching, and error handling systems. Use the load function pattern — it runs on the server for SSR, returns typed data to the page component, and integrates with SvelteKit's navigation and error boundaries.
- Ignoring the Svelte language server and its error messages — Svelte's language server (svelte-language-server) provides inline type checking and template validation in VS Code via the official Svelte for VS Code extension. Developers who ignore template errors or use // @ts-nocheck suppress the most valuable safety net Svelte provides. Install the Svelte for VS Code extension and address language server warnings before deploying.
Best Practices for Production Svelte Applications
The following practices reflect patterns used in production Svelte applications at companies including Datawrapper, The New York Times, and successful SvelteKit-based SaaS products deployed in 2025–2026.
- Use SvelteKit for any project beyond a static demo — SvelteKit provides SSR for SEO, file-based routing, server-side data loading, form actions with progressive enhancement, and deployment adapters for every major platform. The development experience of SvelteKit with Vite and HMR makes it faster to build than a plain Svelte + manual router setup. The only reason to not use SvelteKit is embedding Svelte into an existing non-SvelteKit application.
- Adopt Svelte 5 Runes for all new code — Runes produce cleaner code, better TypeScript inference, and resolve the deep object mutation issues of Svelte 4 reactivity. The lang='ts' attribute on the script block and $props() typed destructuring gives you full IDE autocomplete and type checking for props. Svelte 4's export let syntax is still supported but represents the legacy path.
- Keep components small and single-purpose — Svelte's single-file component format encourages large files with mixed concerns. A component with 300+ lines of script and 200+ lines of template is a signal to decompose. Extract reusable UI elements into components in src/lib/components/, shared logic into .svelte.ts composable functions (the Svelte 5 equivalent of React hooks), and data fetching into SvelteKit load functions.
- Use derived stores and $derived for expensive computations — every reactive value that is computed from other reactive state should be $derived or a derived store. This ensures the computation only runs when its dependencies change, not on every component re-render. Expensive operations (filtering large arrays, computing statistical summaries) inside template expressions run on every render cycle — move them to $derived.
- Scope transitions to layout shifts — Svelte's built-in transitions are zero-cost for transitions you do not use (tree-shaken at build time) but can cause layout instability if applied to elements that affect page flow. Apply transitions primarily to elements that appear and disappear as overlays, modals, or notifications — avoid fly and slide transitions on elements inside the document flow for content that is visible above the fold, as these can affect Core Web Vitals layout shift scores.
- Use SvelteKit's $env/static/private for sensitive environment variables — never access process.env directly in SvelteKit server routes or load functions. Import from $env/static/private instead — SvelteKit guarantees these values are never accidentally bundled into client-side code, even if the import is in a file that also exports client-used code. $env/static/public is for values that are safe to expose to the browser.
- Test with Vitest for unit testing and Playwright for end-to-end — the SvelteKit scaffolding CLI offers both during project creation. Vitest integrates with SvelteKit's Vite configuration for fast unit tests with svelte-testing-library for component testing. Playwright provides browser-level E2E testing of SvelteKit routes, server actions, and full user flows.
Real-World Use Cases and Production Deployments
Svelte's production deployment history in 2025–2026 reveals a consistent pattern: organizations choose it specifically for performance-critical, user-facing UI where bundle size and load time directly impact metrics, or for data visualization contexts where Svelte's clean reactive syntax and fine-grained DOM updates produce the cleanest implementation.
| Company / Project | What They Use Svelte For | Why Svelte | Key Benefit |
|---|---|---|---|
| The New York Times | Interactive data visualizations and graphics published alongside news articles — charts, maps, interactive explainers | Rich Harris (Svelte's creator) was a graphics editor at The Guardian, then The New York Times — built Svelte for exactly this use case. Svelte's reactivity and transition system are optimal for declarative data visualization. | Small bundle sizes for one-off interactive graphics where loading React would be disproportionate overhead. Direct DOM update model maps naturally to SVG and Canvas manipulation. |
| Apple (Podcasts web app, 2024) | The Apple Podcasts web interface launched in 2024 was built with Svelte | Performance requirements for a consumer-facing product at Apple's scale require minimal JavaScript overhead. SvelteKit's SSR ensures fast first-paint. | Zero-runtime compiled output and server-side rendering for fast initial page loads on the Podcasts web app. |
| Spotify | Parts of the Spotify web player UI for faster rendering | Specific UI components requiring high-performance updates — real-time playback state, animated visualizations — benefit from Svelte's direct DOM update model over React's virtual DOM diffing. | Reduced time-to-interactive for playback controls and real-time updating components in the web player. |
| Datawrapper (journalism tool) | The chart creation and editing interface — one of the most widely cited Svelte production case studies | Datawrapper migrated from jQuery and PHP to Svelte using a documented 'inside-out' approach — replacing individual components while keeping the surrounding application intact. The migration demonstrated incremental adoption viability. | Smaller team productivity: Svelte's minimal boilerplate meant a small frontend team could maintain and extend the charting interface faster. Documented 40% less code vs equivalent React implementation. |
| AutoTrader UK | Portions of the user-facing vehicle search and listing interface | Performance on mobile devices for automotive search — users searching for cars often on mobile connections where bundle size directly impacts bounce rate. | Faster page loads for search result pages on mobile devices — directly measurable business impact through bounce rate reduction. |
| Square Enix | Game-related web experiences and promotional pages | High-fidelity animation and transition requirements for game promotional content — Svelte's built-in transition system handles complex animations without adding animation library dependencies. | Zero-dependency animation system capable of matching design specifications without Framer Motion or GSAP. |
| E-commerce startups (multiple) | Mobile-optimized product catalogs where bundle size affects conversion rate | A 2025 case study cited in the Strapi Svelte vs React comparison documented an e-commerce startup choosing Svelte for mobile-optimized catalogs where compile-time optimizations ensured sub-second loads during peak traffic. | Svelte's 30–40% smaller bundles produce measurable conversion rate improvements on mobile — particularly on 3G/4G connections in emerging markets. |
FAQs
Is Svelte good for beginners?
Svelte is arguably the most beginner-friendly major frontend framework in 2026 — its syntax is closest to vanilla HTML, JavaScript, and CSS of any component-based framework. A Svelte component is essentially an HTML file with a script tag and a style tag: you write HTML in the template, JavaScript in the script block, and CSS in the style block. There are no hooks rules to memorize (unlike React's rules about where useState and useEffect can be called), no concept of virtual DOM to understand, no JSX syntax to learn, and no configuration boilerplate required to get a component working. The Stack Overflow 2025 survey of 49,000 developers gave Svelte a 62.4% admired rating — the highest of any framework — which reflects the experience of developers who have actually used it. The State of JS survey documented usage growing from 8% to 20% in two years, partially driven by developers finding Svelte easier to learn than React. The caveat for beginners: JavaScript fundamentals are required before Svelte. Svelte does not simplify JavaScript — it simplifies framework patterns. A developer who does not understand async/await, array methods, and DOM events will find Svelte confusing. With those fundamentals, Svelte's learning curve is genuinely gentler than React or Angular. The smaller ecosystem means beginners encounter problems that have fewer pre-written Stack Overflow answers, so comfort with reading official documentation and the Svelte community Discord is helpful.
Do I need JavaScript knowledge before learning Svelte?
Yes — solid JavaScript fundamentals are necessary before learning any frontend framework including Svelte. Svelte simplifies framework patterns (no virtual DOM, no hooks, minimal boilerplate) but it does not abstract away JavaScript itself. To work effectively with Svelte you need: variables, functions, and objects; array methods (map, filter, reduce) because they appear in {#each} list rendering; async/await and Promises because API calls in SvelteKit load functions and onMount are async; DOM events (click, input, submit) because Svelte's event system binds to them; and ES modules (import/export) because every Svelte component and SvelteKit route uses module syntax. TypeScript knowledge is increasingly expected in 2026 because SvelteKit defaults to TypeScript and Svelte 5's $props() type inference requires TypeScript for full benefit. Practical path: spend 4–6 weeks on JavaScript fundamentals (variables, functions, objects, arrays, async/await, fetch API) before starting Svelte. MDN Web Docs and The Odin Project are reliable free resources for JavaScript fundamentals. Then go through the official Svelte tutorial at svelte.dev/tutorial — it is one of the best framework tutorials available and introduces Svelte concepts in the browser without requiring any local setup.
Is Svelte used in production?
Yes — Svelte is used in production at companies including The New York Times, Apple (Podcasts web app, 2024), Spotify (parts of web player), Netflix (select UI components), AutoTrader UK, Square Enix, and Datawrapper. Stack Overflow itself used Svelte for its 2024 Developer Survey results site — a meaningful signal of production trust from one of the most technically scrutinized web properties. The production adoption pattern is consistent: organizations choose Svelte specifically for user-facing UI where load time and bundle size have direct business impact (e-commerce conversion rates, media site bounce rates, mobile performance metrics) or for interactive data visualization and graphics where Svelte's fine-grained reactivity and built-in transitions produce clean implementations without animation library dependencies. Datawrapper's migration from jQuery and PHP to Svelte is one of the most documented Svelte production case studies — demonstrating incremental adoption and 40% code reduction versus an equivalent React implementation. GitHub stars grew from 32,000 in 2019 to 80,000+ by mid-2025. State of JS usage grew from 8% to 20% in two years. 7.2% of developers in the Stack Overflow 2025 survey (49,000+ respondents) currently use Svelte. The honest assessment: Svelte is in production at high-impact deployments but remains a smaller ecosystem than React or Vue. The job market has roughly 900 Svelte positions versus 110,000+ React positions on LinkedIn — a 122:1 ratio. Svelte is a legitimate production choice for the use cases where it excels; it is not yet the default choice for enterprise teams whose primary concern is hiring velocity.
Is Svelte faster than React?
In measured benchmarks and for the specific characteristics Svelte is optimized for, yes — and the advantage is structural rather than incidental. Svelte's speed advantage has two distinct dimensions. First, bundle size: Svelte compiles components to vanilla JavaScript with zero framework runtime in the output. React ships 45KB+ of runtime code (React + ReactDOM, gzipped) to every user's browser on every page load before any application code runs. Svelte's equivalent baseline is essentially zero. For small to medium applications, this produces 30–40% smaller total JavaScript bundles. For large applications with many components, the gap narrows — Svelte's per-component compiled output grows while React's runtime cost is fixed. Second, runtime update performance: because Svelte knows at compile time exactly which DOM nodes depend on which reactive variables, it updates those nodes directly without virtual DOM diffing. React's update cycle involves re-rendering to a virtual DOM tree, diffing against the previous tree, and then applying mutations — more operations per update, though React's compiler (introduced in React 19) reduces this gap. Svelte 5 startup times benchmark 2–3x faster than React equivalents. However, context matters: React has a compiler in React 19 that applies automatic memoization, closing the performance gap for many patterns. For large-scale complex applications with deeply nested component trees, the practical performance difference between a well-optimized React app and a well-built Svelte app is smaller than headline benchmarks suggest. The bundle size difference is more consistent and directly measurable through Lighthouse scores and Core Web Vitals metrics.
What is Svelte 5 and what changed?
Svelte 5 — released in late 2024 — is the most significant update to Svelte since its creation, introducing a new reactivity system called Runes that replaces the implicit, compiler-magic reactivity of Svelte 4 with explicit, fine-grained reactive primitives. The key changes: Runes replace Svelte 4's reactivity model. Where Svelte 4 made any top-level let variable automatically reactive (implicit, compiler magic), Svelte 5 requires explicit $state() declarations for reactive variables. $derived() replaces the $: reactive declaration syntax. $effect() replaces $: { sideEffect } blocks. $props() replaces export let for receiving component props. The rationale: Svelte 4's implicit reactivity was simple but had edge cases — it did not work in .ts files outside components, deep object property mutations did not trigger updates, and the $: syntax was overloaded to mean both 'reactive declaration' and 'reactive statement'. Runes are explicit, consistent, work in .svelte.ts shared modules, and track deep object mutations correctly. Event handling changed: on:click={handler} in Svelte 4 becomes onclick={handler} in Svelte 5 — standard HTML event attribute names without the on: prefix. Snippets replace slots: Svelte 4 used <slot> for content projection; Svelte 5 uses {#snippet} blocks which are more flexible. Svelte 4 syntax is still supported in Svelte 5 — the migration is opt-in and incremental. New projects should use Svelte 5 Runes. The Svelte 5 migration guide at svelte.dev provides automated codemods for common patterns.
Should I use Svelte or React in 2026?
The choice between Svelte and React in 2026 depends on specific project requirements, team composition, and what you are optimizing for — there is no universal correct answer. Use Svelte when: performance and bundle size are primary concerns (e-commerce conversion, mobile-first apps, media interactive graphics), your team is small and wants minimal boilerplate, you are building a greenfield project where the smaller ecosystem is not a constraint, you value developer experience highly (Svelte's 62.4% admired rating vs React's 52.1% reflects genuine developer satisfaction differences), you are building data visualization or animation-heavy interfaces where Svelte's compiled output and built-in transitions excel, or you are a solo developer or small startup where the joy of development compounds into shipping speed. Use React when: the job market matters — 52% of frontend positions mention React vs a fraction for Svelte; you need maximum ecosystem coverage (React has component libraries, testing utilities, and solutions for virtually every use case that Svelte does not); you are building a React Native mobile application alongside the web app; your team already has React expertise and the productivity loss of switching exceeds the performance gain; or you are at a large enterprise where the talent pool availability and support for React outweighs the technical advantages of Svelte. The honest 2026 verdict: Svelte is technically superior in bundle size and raw performance. React is practically superior in ecosystem, hiring, and long-term enterprise support. For a solo developer or small startup building a performance-critical public-facing product, Svelte is a compelling choice with real business advantages. For a 50-person engineering team hiring Frontend developers at scale, React remains the lower-risk default.
What is SvelteKit and do I need it?
SvelteKit is the official full-stack meta-framework for Svelte — the equivalent of Next.js for React or Nuxt.js for Vue. It adds file-based routing, server-side rendering (SSR), static site generation (SSG), server-side API endpoints, form actions with progressive enhancement, deployment adapters for Vercel/Netlify/Cloudflare/Node.js, and typed route utilities to Svelte. For 90%+ of real-world Svelte projects, yes — you need SvelteKit. The reasons: file-based routing is significantly faster to work with than manually configuring a router; SSR is essential for SEO on content-heavy pages (blog posts, product pages, landing pages); server endpoints let you write backend logic (database queries, API calls with private keys) in the same project without a separate backend service; form actions with progressive enhancement make forms that work without JavaScript — critical for accessibility and reliability; and adapter-auto automatically configures deployment for Vercel, Netlify, and Cloudflare. The cases where you might not use SvelteKit: embedding Svelte into an existing non-SvelteKit application (a legacy PHP or Ruby on Rails app adding Svelte components to specific pages), building a Chrome extension or desktop app where SvelteKit's routing model does not apply, or using Svelte within a larger Vite-based build system that already handles routing. npm create svelte@latest is the single command to start a SvelteKit project — it scaffolds the project with optional TypeScript, ESLint, Prettier, and testing configuration through an interactive CLI prompt.
How does Svelte's reactivity differ from React's state model?
Svelte and React's reactivity models differ in mechanism, syntax, and mental model — and understanding these differences is the key to transitioning from React to Svelte without applying React patterns that produce incorrect Svelte behavior. In React: state is managed through useState which returns a value and a setter function. The setter must be called with the new value or updater function to trigger a re-render. React re-renders the entire component function when state changes, then reconciles the virtual DOM diff. You cannot mutate state objects directly — you must produce a new object (spread syntax or Object.assign). useEffect handles side effects with a dependency array that controls when the effect re-runs. In Svelte 5 with Runes: reactive state is declared with $state(initialValue). The variable itself is reactive — assign to it directly (count++ or user.name = 'Alice') to trigger updates. Deep object property mutations are tracked. There is no setter function, no immutability requirement, no dependency array. The compiler knows which DOM nodes depend on which state variables and generates update functions that patch only those nodes — no component function re-execution, no virtual DOM. $derived replaces useMemo for computed values — it automatically tracks its dependencies and re-evaluates when they change, with no dependency array. $effect replaces useEffect — it also automatically tracks dependencies from the reactive variables accessed inside it, with no dependency array. The cleanup pattern is identical: return a function from $effect for cleanup. The key mental model shift: in React, you cause re-renders by calling setters. In Svelte, you cause updates by reassigning reactive variables. Svelte's compiler is aware of these assignments and has generated the exact DOM update code needed for each one.
