> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pult.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Resources

> Teach Pult how to fetch, find, list and show the records in your app.

A resource is a kind of record in your app: users, organizations, orders, repositories. You give Pult a few functions you mostly already have, and every record gets a page in the console with its details, its history, the items about it and the actions your team can run on it.

```ts theme={null}
import { b, resource } from "pult"
import { z } from "zod"

export const user = resource("user", {
  icon: "user",
  get: (id) => db.users.find(id),
  find: (query) => db.users.search(query),
  list: {
    filters: z.object({ plan: z.enum(["free", "pro", "team"]).optional() }),
    run: ({ query, filters, cursor, limit }) =>
      db.users.page({ query, ...filters }, cursor, limit),
  },
  title: (u) => u.username,
  subtitle: (u) => u.email,
  fields: (u) => ({ plan: u.plan, joined: u.createdAt }),
  url: (u) => `https://acme.com/admin/users/${u.id}`,
  render: (u) => [
    b.fields({
      email: b.sensitive(u.email),
      plan: u.plan,
      joined: u.createdAt,
    }),
  ],
  related: {
    orders: { resource: "order", list: (u) => db.orders.forUser(u.id) },
  },
  actions: (action) => ({
    // see Actions
  }),
})
```

Put `get` and `find` before `title` and `render`, so TypeScript knows the record type by the time it reaches them.

## Fetching

`get(id)` returns the record or nothing. It runs in your app whenever Pult needs the record: rendering its page, checking which actions apply, running one. Records are identified by `record.id`; pass `id: (record) => ...` if yours are keyed differently.

`title` names a record everywhere it appears. `subtitle` adds a line in search results and pickers.

## Finding and browsing

`find(query, limit)` powers search: the resource's page in the console, ⌘K and record pickers in action forms. Without it, a resource can't be searched.

`list` lets people browse records instead of searching for one. `run` receives the search text, the filters people picked and a cursor, and returns `{ records, cursor }`; pass back a cursor to offer another page, or `null` when there's no more. `filters` is a schema whose enum and boolean fields become filter buttons and whose text and number fields become inputs.

`fields(record)` picks what the browse table shows and what related lists show.

Selecting rows in the table runs any of the resource's actions on all of them at once.

## Showing a record

`render(record)` returns [blocks](/build/blocks) for the record's page. It runs in your app each time the page opens, so it's always current.

`url(record)` adds an "Open in your app" link to the page, for when your own admin has more.

## Related records

`related` lists records connected to this one. Each relation names a resource and lists its records:

```ts theme={null}
related: {
  repos: {
    resource: "repo",
    label: "Repositories",
    list: (u) => db.repos.byOwner(u.id),
  },
  messages: {
    resource: "message",
    list: (u, limit) => db.messages.byAuthor(u.id, limit),
  },
},
```

They show as tables on the record's page, linked to their own pages. Resources refer to each other by name, so two resources can point at each other without an import cycle; `pult check` catches a name that doesn't exist.

## History

A record's page shows everything done to it in Pult: actions, approvals and reveals. Your app can add its own events with `pult.log`; see [Hooks and history](/build/hooks).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.