# Loaders and Deferred Values

> Load route data before render, and mark the slow parts deferred so they do not block the first paint.

Source: [https://askrjs.com/docs/routing/loaders-and-deferred](https://askrjs.com/docs/routing/loaders-and-deferred)

Status: stable. Packages: @askrjs/askr.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Return critical loader data directly and wrap slower independent work in defer so the page can stream a stable shell.

```tsx
import { defer } from '@askrjs/askr/router';

route('/projects/{projectId}', ProjectPage, {
  loader: async ({ params }) => ({
    project: await projects.get(params.projectId),
    activity: defer(activity.list(params.projectId)),
  }),
});
```

## Route loaders

`RouteOptions.loader` is a function that receives the route's `RouteContext` plus an optional `request`, and its return value becomes the data available to the route on first render — including during SSR, where it runs before the response streams. `preload` is a separate hook meant for warming query caches ahead of render rather than blocking on the result, and it's handed a `QueryPrefetchContext` alongside the usual context fields. Both run per-navigation, keyed to the route that's about to become active, not on some global schedule.

## Deferred values

`defer(promise)` wraps a `PromiseLike<T>` into a `Deferred<T>` you can return from a loader without blocking the initial render on it — the page renders immediately and the deferred value resolves in the background. `isDeferred()` checks whether a given value is one of these wrappers, which loaders and data-fetching code use to decide whether to await it directly or hand it to `Resolve`. `routeData<T>()` reads whatever the current route's loader returned, deferred values included, from inside the rendering component.

## Pending and rejected states

A `Deferred<T>` exposes its own `state` (`'pending' | 'fulfilled' | 'rejected'`), plus `value` and `error` fields that update as the underlying promise settles. The `Resolve` component is the declarative way to render against that state: give it a `value`, a `pending` fallback, an optional `rejected` fallback (a node or a function of the error), and a `children` render function that only runs once the value is fulfilled. That keeps loading and error UI colocated with the data they describe instead of scattered across manual `if` checks.

## Cancellation

Every loader and `preload` call gets a `signal: AbortSignal` on its context, and Askr aborts it automatically if a newer navigation supersedes the one that triggered it — so a slow loader for a route the user already navigated away from doesn't finish late and overwrite current state. `resolveDeferredValues(input, signal)` walks a data structure and resolves any nested `Deferred` values it finds, respecting that same signal so a whole tree of pending data can be cancelled together rather than one promise at a time.

## Documentation navigation

[Previous](https://askrjs.com/docs/routing/navigation-and-url-state/index.md) | [Next](https://askrjs.com/docs/routing/access-policies/index.md)
