Skip to content

Data Loading ​

Route loaders fetch data before the component renders. They integrate with the mesh resource system.

Loader ​

ts
{
  path: "/products/:id",
  component: () => import("./ProductDetail"),
  loader: async ({ params, mesh, signal }) => {
    return mesh.resource("product.detail").fetch({ id: params.id }, { signal });
  }
}

The loader receives:

  • params — path parameters
  • mesh — the mesh instance
  • signal — AbortSignal (aborted if navigation is cancelled)

Dependencies ​

Prefetch data in parallel with the main loader:

ts
{
  path: "/orders/:id",
  loader: async ({ params, mesh }) => mesh.resource("order.detail").fetch({ id: params.id }),
  dependencies: {
    customer: (params, mesh) => mesh.resource("customer.detail").fetch({ id: params.customerId }),
    products: (params, mesh) => mesh.resource("products.list").fetch()
  }
}

Dependencies run in parallel with the main loader. If data is already cached, the dependency resolves instantly.

Routes with rollback: true revert the entire navigation if the loader fails:

ts
{
  path: "/checkout",
  rollback: true,
  loader: async ({ mesh }) => {
    return mesh.resource("checkout.summary").fetch();
    // If this throws, the URL reverts to the previous route
  }
}

No broken page is ever shown. The user stays on the previous route.

Error Recovery ​

Auto-retry failed loaders:

ts
{
  path: "/dashboard",
  loader: async ({ mesh }) => mesh.resource("dashboard.data").fetch(),
  errorRecovery: {
    retry: 3,
    retryDelay: backoff({ base: 1000, max: 10000 }),
    fallbackComponent: () => import("./DashboardSkeleton"),
    onError: (error) => console.error("Dashboard load failed:", error)
  }
}

Pending UI ​

Show a loading state while the loader runs:

ts
{
  path: "/products",
  component: () => import("./Products"),
  pendingComponent: () => import("./ProductsLoading"),
  loader: async ({ mesh }) => mesh.resource("products.list").fetch()
}

The pendingComponent is shown after defaultPendingMs (default: 200ms) to avoid flash.

Error UI ​

Show a custom error component when the loader fails:

ts
{
  path: "/products/:id",
  component: () => import("./ProductDetail"),
  errorComponent: () => import("./ProductError"),
  loader: async ({ params, mesh }) => mesh.resource("product.detail").fetch({ id: params.id })
}

Important Notes ​

TIP

Loaders run before the component renders. The component receives loader data via useMatch().data.

WARNING

Always pass the loader's signal to your fetch calls. This ensures cancelled navigations don't waste network requests.

Next Steps ​

Released under the MIT License.