Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jpcutshall/svelte5-router/llms.txt

Use this file to discover all available pages before exploring further.

The dynamic function enables code-splitting at the route level. Wrap a dynamic import() expression with dynamic() and pass the result as the component prop on a <Route>. The router will defer loading the component’s JavaScript and CSS until that route is first matched, producing smaller initial bundles and faster first-paint times for large applications. While the component is loading the route renders nothing; once the import resolves the component mounts; if the import rejects the route renders an error paragraph with the rejection message.

Import

import { dynamic } from 'svelte5-router';

Signature

function dynamic(p: Promise<unknown>): AsyncComponent

AsyncComponent type

type AsyncComponent = () => Promise<{
  default: Component<any, Record<string, unknown>>;
}>;
AsyncComponent is a named function (internally called loaderComponent) whose prototype carries a name property set to "dynComponent". The router uses this marker — via the isAsync guard — to distinguish lazy components from regular synchronous Svelte components, both of which are plain functions in Svelte 5.

Parameters

p
Promise<unknown>
required
A Promise produced by a dynamic import() expression, e.g. import('./routes/About.svelte'). The promise must resolve to a module with a default export that is a Svelte component. You can pass the raw import() call directly — no .then() chaining is needed.

Return value

AsyncComponent
() => Promise<{ default: Component }>
A named loader function that, when called by the <Route> component, returns the original promise. The <Route> component awaits this promise using Svelte’s {#await} block.

Loading lifecycle

When a <Route> receives an AsyncComponent as its component prop, it:
  1. Calls isAsync(component) — checks for the "dynComponent" prototype marker.
  2. Invokes the loader function to obtain the promise.
  3. Renders nothing while the promise is pending ({#await} pending block is empty).
  4. Renders <C.default {...routeParams} /> once the promise resolves.
  5. Renders <p>{error.message}</p> if the promise rejects.
<!-- Simplified Route.svelte internals -->
{#if PropComponent && PropComponent instanceof Function}
  <PropComponent {...routeParams} />
{:else if PropComponent && PropComponent instanceof Promise}
  {#await PropComponent then C}
    <C.default {...routeParams} />
  {:catch error}
    <p>{error.message}</p>
  {/await}
{:else}
  {@render children?.(routeParams)}
{/if}
The pending state renders nothing by default. If you want a loading indicator, wrap the <Route> in your own {#await} or use a Suspense-style wrapper component around the lazy route.

Examples

<script lang="ts">
  import { Router, Route, dynamic } from 'svelte5-router';

  const AboutRoute = dynamic(import('./routes/About.svelte'));
</script>

<Router>
  <Route path="/about" component={AboutRoute} />
</Router>

Why a named function?

In Svelte 5, components are plain functions, so the router cannot distinguish component={MyComponent} (synchronous) from component={dynamic(...)} (asynchronous) by type alone. dynamic solves this by creating a named inner function and assigning "dynComponent" to loader.prototype.name. The isAsync guard then checks:
function isAsync(fn: Function | undefined): fn is AsyncComponent {
  if (!fn) return false;
  return !!(fn.prototype && 'name' in fn.prototype && fn.prototype.name === 'dynComponent');
}
This lightweight marker avoids any runtime overhead and works without needing the component to carry a special type brand.
Call dynamic(import('./Route.svelte')) at the module level (outside $state, $effect, or event handlers) so that the import promise is created once and shared across all renders. Creating the promise inside a reactive block would restart the import on every re-evaluation.

Build docs developers (and LLMs) love