Svelte

Compile-time UI framework - no virtual DOM, surgically precise updates, smallest bundle sizes

TL;DR

One-liner: Svelte is a compiler, not a framework - your code becomes vanilla JS with zero runtime overhead.

Core Strengths:

  • No virtual DOM - compiles to surgical DOM updates
  • Truly reactive - just assign to trigger updates
  • Smallest bundles - no framework code shipped
  • Svelte 5 runes - fine-grained reactivity primitives

Core Concepts

Concept 1: Compiler, Not Runtime

Svelte shifts work from browser to build time. Your components compile to efficient JavaScript that directly manipulates the DOM.

<!-- This compiles away completely -->
<script>
  let count = $state(0);
</script>

<button onclick={() => count++}>{count}</button>

Concept 2: Runes (Svelte 5)

Runes are the new reactivity system. They’re function-like macros that the compiler understands.

<script>
  let count = $state(0);           // Reactive state
  let doubled = $derived(count * 2); // Computed value

  $effect(() => {
    console.log(count);  // Runs when count changes
  });
</script>

Concept 3: Single-File Components

Everything in one .svelte file - script, markup, styles (scoped by default).

<script>
  let name = $state('world');
</script>

<h1>Hello {name}!</h1>

<style>
  h1 { color: purple; }  /* Only affects this component */
</style>

Quick Start

Create Project

npx sv create my-app
cd my-app
npm install
npm run dev

Project Structure

my-app/
├── src/
│   ├── routes/        # SvelteKit pages
│   │   └── +page.svelte
│   ├── lib/           # Shared components
│   └── app.html
├── svelte.config.js
└── package.json

Minimal Example

<!-- src/routes/+page.svelte -->
<script>
  let count = $state(0);
</script>

<h1>Hello Svelte!</h1>
<button onclick={() => count++}>
  Count: {count}
</button>

Run

npm run dev
# Open http://localhost:5173

Gotchas

Reactivity requires $state (Svelte 5)

<script>
  // ❌ Not reactive
  let count = 0;

  // ✅ Reactive with runes
  let count = $state(0);
</script>

Arrays/objects need reassignment or $state

<script>
  let items = $state([1, 2, 3]);

  // ✅ Direct mutation works with $state in Svelte 5
  items.push(4);

  // Or reassign
  items = [...items, 4];
</script>

Props use $props()

<script>
  // Svelte 5 way
  let { name, count = 0 } = $props();
</script>

<h1>Hello {name}! Count: {count}</h1>

Two-way binding

<script>
  let value = $state('');
</script>

<!-- bind: creates two-way binding -->
<input bind:value>
<p>You typed: {value}</p>

When to Use

Best for:

  • Performance-critical applications
  • Small to medium projects
  • Developers who dislike framework overhead
  • Learning modern reactivity concepts

Not ideal for:

  • Teams needing maximum ecosystem/hiring pool (React leads)
  • Projects requiring extensive third-party integrations
  • Very large enterprise apps (less battle-tested at scale)

Comparison:

FeatureSvelteReactVue
Bundle sizeTiny40KB30KB
RuntimeNoneYesYes
Learning curveEasyMediumEasy
ReactivityCompile-timeHooksProxy-based

Next Steps

Cheatsheet

PatternSvelte 5 Syntax
Statelet x = $state(0)
Derivedlet y = $derived(x * 2)
Effect$effect(() => { ... })
Propslet { prop } = $props()
Bind<input bind:value>
Eventonclick={handler}
Condition{#if x}...{/if}
Loop{#each items as item}...{/each}
Await{#await promise}...{/await}