loader$()

Loaders allow data to flow from the server to the Qwik Components. For this reason, Qwik Loaders should be always understood in the context of loading data in the server that is later consumed by a Qwik Component, if you want to create a RESTful endpoint, please check the endpoints guide instead.

They behave like RPC server-side functions that can be invoked by Qwik Components during rendering.

Declaring a loader

Loaders can only be declared inside the src/routes folder, in a layout.tsx or index.tsx file, and they MUST be exported.

// src/routes/layout.tsx
import { loader$ } from '@builder.io/qwik-city';

export const getProductData = loader$(() => {
  return {
    product: {
      name: 'Qwik City',
      price: 100,
    },
  };
});

Loaders are not endpoints, it's an internal communication channel between the server and the Qwik Components. Also, loaders must return a JSON serializable value.

Using a loader

Loaders can be used by any component in the application, as long as the loader is declared in a layout.tsx or index.tsx file that is part of the existing route.

// src/routes/index.tsx
import { loader$ } from '@builder.io/qwik-city';
import { component$ } from '@builder.io/qwik';

export const useGetServerTime = loader$(() => {
  return {
    time: Date.now();
  }
});

export default component$(() => {
  // Retrieve a reactive signal of the loader data
  const signal = useGetServerTime(); // Signal<{time: number}>
  return (
    <div>
      Server time: {signal.value.time}
    </div>
  );
});

The useGetServerTime() retrieves the loader data, but it does not execute the loader multiple times. Loaders execute eagerly\ at the beginning of the request in order to provide low latency. For this reason they are only allowed in the src/routes folder, in a layout.tsx or index.tsx file, and they MUST be exported.

Multiple loaders

Multiple loaders are allowed across the whole application, and they can be used in any Qwik Component. You can even declare multiple loaders in the same file.

File: src/routes/layout.tsx

import { component$ } from '@builder.io/qwik';
import { loader$ } from '@builder.io/qwik-city';
import { Footer } from '../components/footer.tsx';

export const useGetServerTime = loader$(() => {
  return {
    time: Date.now();
  }
});

export default component$(() => {
  const signal = useGetServerTime();
  return (
    <main>
      <Slot>
      <Footer />
    </main>
  );
});

File: src/components/footer.tsx

import { component$ } from '@builder.io/qwik';

// Import the loader from the layout
import { useGetServerTime } from '../routes/layout.tsx';

export const Footer = component$(() => {
  // Consume the loader data
  const signal = useGetServerTime();
  return <footer>Server time: {signal.value.time}</footer>;
});

File: src/routes/admin/index.tsx

import { component$ } from '@builder.io/qwik';
import { loader$ } from '@builder.io/qwik-city';

export const useIsLogged = loader$(({cookie}) => {
  return {
    logged: checkcookie(cookie);
  }
});

export const useGetCurrentUser = loader$(({cookie}) => {
  return {
    user: currentUserFromcookie(cookie);
  }
});

export default component$(() => {
  const logged = useIsLogged();
  const user = useGetCurrentUser();
  return (
    <section>
      <h1>Admin</h1>
      {logged.value.logged ? (
        <p>Welcome {user.value.user.name}</p>
      ) : (
        <p>You are not logged in</p>
      )}
    </section>
  );
});

Loader context

Just like request handlers such as onRequest and onGet, loaders have access to the RequestEvent object which includes information about the current request.

This information comes in handly when the loader needs to conditionally return data based on the request, or it needs to override the response status, headers or body manually.

import { loader$ } from '@builder.io/qwik-city';

export const getServerTime = loader$((ev) => {
  console.log('Request headers:', ev.headers);
  console.log('Request cookies:', ev.cookie);
  console.log('Request url:', ev.url);
  console.log('Request method:', ev.method);
  console.log('Request params:', ev.params);

  return {
    time: Date.now();
  }
});

When to use a loader?

A loader should be used when you need to provide some server-side data to your Qwik Components. For example, if you need to fetch some data from a database or an API, you can use a loader to do that.

You should not use a loader to create a REST API, for that you’d be better off using an Endpoint, which allows you to have tight control over the response headers and body.

Made with ❤️ by