OOlgax DXP
Guides

Data sources

Feed real Payload collection data into Olgax DXP page-builder blocks with @olgax.com/datasource - resolvers, route handlers and the RelatedPages example.

@olgax.com/datasource is a deliberately narrow resolver layer. A block declares "pull N items from a Payload collection, filtered by one field", and receives them as a resolved items prop.

It supports one equality filter and a limit. It is not a query language.

How it works

The editor sets three things on the block: collection, optionally filterField and filterValue, and limit. When they change, Puck's resolveData fetches the items and writes them into a read-only items prop.

lib/puck.config.tsx
import { createCollectionResolverFetch } from "@olgax.com/datasource";
import { registerRelatedPages } from "@olgax.com/components";

registerRelatedPages(createCollectionResolverFetch("/api/related-pages"));
app/(frontend)/api/related-pages/route.ts
import { NextResponse } from "next/server";
import { queryCollectionFromSearchParams } from "@olgax.com/datasource";
import { getPayloadClient } from "@/lib/payload";

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const items = await queryCollectionFromSearchParams(getPayloadClient, searchParams);
  return NextResponse.json(items);
}

The scaffolded site already includes this route and registration, so the RelatedPages block works out of the box.

Which resolver should I use?

FunctionUse when
createCollectionResolverFetch(endpoint)Default. The config is shared with the client-side editor. It only calls fetch(), so payload never reaches the browser bundle.
createCollectionResolver(getPayload)Only for a config that exclusively backs server-rendered output and never ships to the client

Build a data-backed block

Spread collectionQueryFields into your block's fields, and use the matching resolver as resolveData:

components/blocks/LatestPages.tsx
import type { ComponentConfig } from "@puckeditor/core";
import {
  collectionQueryFields,
  createCollectionResolverFetch,
  type CollectionQueryProps,
} from "@olgax.com/datasource";

type Item = { id: string | number; title?: string };
type LatestPagesProps = CollectionQueryProps & { items?: Item[] };

export const latestPagesBlock: ComponentConfig<{ props: LatestPagesProps }> = {
  fields: { ...collectionQueryFields },
  defaultProps: { collection: "pages", limit: 3 },
  resolveData: createCollectionResolverFetch<LatestPagesProps>("/api/related-pages"),
  render: ({ items }) => (
    <ul>
      {(items ?? []).map((item) => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  ),
};

Register it in components/blocks/index.ts like any other block. RelatedPages in @olgax.com/components is the reference implementation.

See the datasource reference for every export.

Think about access

The route handler runs a real Payload query. Keep your collection access rules strict, and do not expose a collection through a public endpoint unless its data is safe to show to anyone.

Questions, ideas or something not working?

Ask in our official Discord, open an issue on GitHub, or edit this page.

On this page