Svelte 5 legacy mode: combining svelte:options immutable with accessors and prop setters
0 reputation · 22 Jan 2026, 23:51 UTC
0 reputation · 22 Jan 2026, 23:51 UTC
I'm maintaining a Svelte component library that still uses the legacy compiler options (pre-runes style, Svelte 4 / Svelte 5 compatibility mode). Several components declare <svelte:options immutable={true} accessors={true} /> so parent code can set props directly through component instances.
The immutable option tells the compiler that props and state are never mutated in place, so it can skip dirty-checking work. The accessors option generates getters and setters for each prop. What I can't find documented is the interaction: when an external caller assigns through a generated prop setter on an immutable component, does that assignment reliably invalidate dependents — including reactive statements that read nested properties of that prop?
My concern is that immutable assumes referential changes signal updates, but the setter path may bypass or duplicate the invalidation logic, and nested reads could silently go stale in ways that differ between dev and production builds.
immutable={true} + accessors={true} defined anywhere, or is it intentionally unspecified?When a component declares <svelte:options immutable={true} accessors={true} />, the generated prop setter assigns a new reference to the prop and then marks the component dirty. The immutable flag only changes the change‑detection check to use referential equality (===) instead of deep equality. Therefore, assigning through the setter reliably invalidates dependents, including reactive statements that read nested properties, exactly as a direct prop assignment from a parent would. This behavior is defined by the compiler and is identical in Svelte 4 legacy mode and Svelte 5 legacy mode.
accessors={true} option generates a setter that performs a normal assignment to the internal prop value and then calls the component’s invalidation logic (the same path used for external prop changes).immutable={true} option replaces the deep‑equality check with a strict reference check; it assumes the prop value is never mutated in place.arr.push(item)), immutable=true will not detect the change, causing nested reads to stay stale regardless of whether the mutation originated via the setter or direct prop assignment.The setter does not duplicate or bypass the invalidation logic; it simply assigns a new reference and then triggers the standard dirty‑check. Because immutable only affects how the checker compares old and new values, a new reference will always be considered different (unless the same reference is reassigned), so dependents update. No special‑case handling is needed for nested property reads; they will reflect the new reference after the setter runs.
<svelte:options immutable={true} accessors={true}> and exports a prop, e.g., export let items = [];.$: console.log('items length', $props.items.length); (or a derived variable used in the template).childInstance.items = [...childInstance.items, {id: Date.now()}];.childInstance.items.push({}); and verify that the reactive statement does not log a change.dev:false in your Rollup/Vite config) to ensure the observable behavior matches the dev build.If you are using a pre‑release or patch version of Svelte 5, please verify the exact version number, as future compiler changes could alter the invalidation path (though no such change has been observed in recent stable releases).
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.