Command Palette

Search for a command to run...

Querying

Fetch data on the server with the client from createPyloServer or createPyloNode, or in Client Components with the React Query hooks. All of them share the same select and filter API.

Server

List

app/projects/page.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 import { pylo } from '@/lib/pylo'; const { data, pagination } = await pylo.project.list({ select: { id: true, name: true, created_at: true, }, pagination: { page: 1, per_page: 20 }, }); // data: Array<{ id: string; name: string | null; created_at: string }> // pagination: { total, current_page, per_page, last_page, has_more_pages }

Omit select to get all scalar fields.

By ID

example.ts
1 2 3 4 5 6 7 8 9 10 11 const project = await pylo.project.byId('project-uuid', { select: { id: true, name: true, customer: { select: { id: true, name: true }, }, }, }); // Returns null if not found

Client hooks

usePyloList

components/project-list.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 'use client'; import { pylo } from "@/lib/pylo-hooks"; export function ProjectList() { const { data, pagination, isLoading, error } = pylo.usePyloList('project', { select: { id: true, name: true, created_at: true }, pagination: { page: 1, per_page: 20 }, filter: { sortby: [{ field: 'created_at', order: 'desc' }], }, }); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error: {error.message}</div>; return ( <div> {data?.map((project) => ( <div key={project.id}>{project.name}</div> ))} <p>Page {pagination?.current_page} of {pagination?.last_page}</p> </div> ); }
FieldTypeDescription
dataT[] | undefinedEntities matching the select
paginationPaginationData | undefinedPagination metadata
isLoadingbooleanTrue while the initial request runs
errorError | nullError if the request failed
refetch() => voidTrigger a refetch

usePyloById

Disabled while id is null or undefined.

components/project-detail.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 'use client'; import { pylo } from "@/lib/pylo-hooks"; export function ProjectDetail({ projectId }: { projectId: string }) { const { data: project, isLoading } = pylo.usePyloById('project', projectId, { select: { id: true, name: true, customer: { select: { id: true, name: true } }, }, }); if (isLoading) return <div>Loading...</div>; if (!project) return <div>Not found</div>; return ( <div> <h1>{project.name}</h1> <p>Customer: {project.customer?.data.name}</p> </div> ); }

usePyloInfiniteList

Infinite scrolling built on useInfiniteQuery.

components/infinite-list.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 'use client'; import { pylo } from "@/lib/pylo-hooks"; export function InfiniteProjectList() { const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = pylo.usePyloInfiniteList('project', { perPage: 20, select: { id: true, name: true }, filter: { sortby: [{ field: 'created_at', order: 'desc' }], }, }); if (isLoading) return <div>Loading...</div>; return ( <div> {data?.data.map((project) => ( <div key={project.id}>{project.name}</div> ))} {hasNextPage && ( <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}> {isFetchingNextPage ? 'Loading...' : 'Load more'} </button> )} </div> ); }

Select

You get back the fields you set to true, and the result type matches that selection.

example.ts
1 2 select: { id: true, name: true } // -> { id: string; name: string | null }

Relations

Include relations with a nested select:

example.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 select: { id: true, // hasOne: pick specific fields customer: { select: { id: true, name: true }, }, // hasMany: with filter and pagination invoices: { select: { id: true, amount_net: true }, pagination: { per_page: 5 }, filter: { sortby: [{ field: 'created_at', order: 'desc' }], }, }, }

Response shapes:

  • hasOne (ManyToOne, OneToOne): { data: { ... } } | null
  • hasMany (OneToMany, ManyToMany): { data: [...], pagination: { ... } }

Error handling

The server client throws PyloError:

example.ts
1 2 3 4 5 6 7 8 9 10 import { PyloError } from '@pylo/nextjs'; try { const { data } = await pylo.project.list(); } catch (error) { if (error instanceof PyloError) { console.error(error.message); console.error(error.graphqlErrors); } }

The hooks return an error state instead of throwing.