Describe the bug
With compilerOptions.experimental.async: true, a destination route's +page is instantiated twice on a single client-side navigation — its onMount runs twice, and the first instance is created, rendered, then torn down again while still reactively alive (which surfaces as derived_inert warnings in a real app). With the flag off, it mounts once.
There are no await expressions in the reproduction, so this is not about async data or update coordination — only the experimental.async rendering machinery's mount/teardown.
Three conditions are required together (removing any one → single mount):
- A persistent layout renders a snippet teleported up from a descendant — the descendant registers a snippet via a context store, and the persistent layout renders it elsewhere in its own tree (a portal); the layout survives the navigation.
- The outgoing route teleports its own child route (
{@render children()}) through that persistent layout.
- The destination is a 2-level route (
+layout + +page).
Only the destination +page leaf doubles; its +layout and the persistent host mount once. It is specifically the persistent host rendering the outgoing route's teleported snippet, concurrent with the navigation — deleting just that {@render slot.teleported()} (keeping everything else) makes it mount once, and rendering a host-owned snippet in the same spot does not trigger it.
Reproduction
https://github.com/torrfura/sveltekit-async-double-mount
npm install && npm run dev # http://localhost:5173
Open the console, click /teleporter, then click /nested. The single /teleporter → /nested navigation mounts nested/+page twice. The on-page panel resets per navigation and shows a verdict, so there's nothing cumulative to misread.
Controls (each removes one condition → single mount):
| Navigation |
Outgoing teleports its child? |
Destination |
dest +page mounts |
/teleporter → /nested |
yes |
2-level |
twice |
/teleporter → /flat |
yes |
1-level |
once |
/inline → /nested |
no |
2-level |
once |
Logs
### Logs
🐛 DOUBLE MOUNT: nested/+page mounted 2× in one navigation → /nested
System Info
System:
OS: macOS 26.5.1
Binaries:
Node: 24.14.0
npm: 11.9.0
npmPackages:
svelte: 5.56.3
@sveltejs/kit: 3.0.0-next.4
@sveltejs/vite-plugin-svelte: 7.1.2
vite: 8.0.16
Severity
annoyance
Additional Information
This stems from ideas like these: #627 But in our case it's about layout orchestration and animation using view transitions.
Describe the bug
With
compilerOptions.experimental.async: true, a destination route's+pageis instantiated twice on a single client-side navigation — itsonMountruns twice, and the first instance is created, rendered, then torn down again while still reactively alive (which surfaces asderived_inertwarnings in a real app). With the flag off, it mounts once.There are no
awaitexpressions in the reproduction, so this is not about async data or update coordination — only theexperimental.asyncrendering machinery's mount/teardown.Three conditions are required together (removing any one → single mount):
{@render children()}) through that persistent layout.+layout++page).Only the destination
+pageleaf doubles; its+layoutand the persistent host mount once. It is specifically the persistent host rendering the outgoing route's teleported snippet, concurrent with the navigation — deleting just that{@render slot.teleported()}(keeping everything else) makes it mount once, and rendering a host-owned snippet in the same spot does not trigger it.Reproduction
https://github.com/torrfura/sveltekit-async-double-mount
Open the console, click /teleporter, then click /nested. The single
/teleporter → /nestednavigation mountsnested/+pagetwice. The on-page panel resets per navigation and shows a verdict, so there's nothing cumulative to misread.Controls (each removes one condition → single mount):
+pagemounts/teleporter → /nested/teleporter → /flat/inline → /nestedLogs
System Info
Severity
annoyance
Additional Information
This stems from ideas like these: #627 But in our case it's about layout orchestration and animation using view transitions.