Open-Source Wikis

/

Svelte

/

Features

/

Legacy compatibility

sveltejs/svelte

Legacy compatibility

Active contributors: Rich Harris, Simon H

Purpose

Svelte 5 ships full backward compatibility with Svelte 3/4 components. A component without runes runs in legacy mode with the original semantics: export let prop, $: reactive labels, auto-subscribed stores ($count), createEventDispatcher, and slot= named slots.

This page collects the legacy machinery so contributors know where each piece lives.

Legacy detection

Mode detection happens during analysis in packages/svelte/src/compiler/phases/2-analyze/index.js. A component is legacy unless:

  • it uses any rune ($state, $derived, etc.), or
  • <svelte:options runes> is set, or
  • the compile option runes: true is passed.

In legacy mode, the analyzer treats let foo = ... at instance-level as reactive in the Svelte 4 sense (mutations re-render), and $: y = ... as a reactive declaration.

legacy_mode_flag

packages/svelte/src/internal/flags/legacy.js exposes a legacy_mode_flag. When the compiler emits a legacy-mode component, it imports this flag, which switches the runtime onto compatibility paths in:

  • packages/svelte/src/internal/client/legacy.js — captured signals tracking for $:.
  • packages/svelte/src/internal/client/dom/legacy/init.js, lifecycle.js, event-modifiers.js, misc.js (legacy event listener bubbling, props update propagation).
  • packages/svelte/src/legacy/legacy-client.js and legacy-server.js — the Svelte 4 component class shim (createClassComponent).

Legacy public API

packages/svelte/src/legacy/legacy-client.js (8 KB) and legacy-server.js (4 KB) export createClassComponent and other helpers that wrap a Svelte 5 component as a Svelte 4-style class with .$set, .$on, .$destroy, etc. This is what @sveltejs/svelte-virtual-list and other libraries built against Svelte 4 use unchanged.

Auto-subscribe stores

The $store shorthand auto-subscribes to a store while a reactive scope is active. The runtime piece is packages/svelte/src/internal/client/reactivity/store.js. The compiler emits store_get(store, '$store') in legacy mode. In runes mode the same shorthand is an error and you must use fromStore(store) instead.

Reactive declarations ($:)

A $: label rewrites to a legacy_pre_effect (or legacy_pre_effect_reset for reset semantics) at the instance level. Implementation in internal/client/reactivity/effects.js. The dependency tracking is the same Reaction graph used by runes — the legacy flow just opts into a different scheduling order.

createEventDispatcher

createEventDispatcher is exported from packages/svelte/src/index-client.js and is marked deprecated. It walks component_context.s.$$events and dispatches a synthetic CustomEvent to each listener. Replacement: callback props or $host().

Migration codemod

The Svelte 4 → 5 codemod is packages/svelte/src/compiler/migrate/index.js (~2k lines). Exposed as svelte/compiler#migrate. It rewrites:

  • export let foolet { foo } = $props().
  • $: y = exprlet y = $derived(expr) when safe.
  • $: { ... }$effect(() => { ... }) when safe.
  • Inline $store reads → fromStore(store).current when needed.
  • createEventDispatcher calls → callback prop suggestions (with manual review nudge).

The migration tool re-uses the parser, scope analyzer, and magic-string to produce a textual rewrite.

Tests

  • packages/svelte/tests/runtime-legacy/ exercises the compatibility runtime.
  • packages/svelte/tests/migrate/ covers the codemod with _input.svelte / _output.svelte pairs.
  • Top-level pnpm test runtime-legacy is the canonical filter.

Key source files

File Purpose
packages/svelte/src/internal/flags/legacy.js legacy_mode_flag setter.
packages/svelte/src/internal/client/legacy.js Captured-signals tracking for legacy $:.
packages/svelte/src/internal/client/dom/legacy/init.js Legacy component init (lifecycle ordering).
packages/svelte/src/internal/client/dom/legacy/lifecycle.js beforeUpdate / afterUpdate integration.
packages/svelte/src/internal/client/dom/legacy/event-modifiers.js once, preventDefault, self, stopImmediatePropagation, stopPropagation, trusted.
packages/svelte/src/internal/client/reactivity/store.js Auto-subscribe store helpers.
packages/svelte/src/legacy/legacy-client.js createClassComponent.
packages/svelte/src/compiler/migrate/index.js Svelte 4 → 5 migration codemod.

Entry points for modification

Legacy support is intentionally frozen. Bug fixes go into the relevant compatibility file. New features should not depend on legacy_mode_flag — runes mode is the default Svelte 5 surface. The migration codemod is the most-touched file in this set; if you find a Svelte 4 idiom it doesn't handle, add a sample under packages/svelte/tests/migrate/samples/ and extend migrate/index.js.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Legacy compatibility – Svelte wiki | Factory