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

# Pages

> Give your app full pages of its own inside Attio

A page is a full screen that belongs to your app. It has its own URL, shows up in the Apps section of the sidebar, and gets the whole content area to itself. Use pages for dashboards, overviews, and anything that isn't about one record. For UI tied to a single record, use a [record tab](../extensions/record-tab) instead.

Pages are defined with [`Extensions.definePage`](./define-page) and laid out with [`Grid`](../components/grid), [`Card`](../components/card) and [`Stack`](../components/stack). For a worked example, see [Building app pages](../guides/building-app-pages).

## File convention

Pages live under `src/app/pages/`. Each page is a folder holding a `page.tsx` that default-exports a `definePage` call:

```text theme={"system"}
src/
└── app/
    └── pages/
        ├── dashboard/
        │   ├── page.tsx            # default-exports Extensions.definePage(...)
        │   └── pipeline-chart.tsx  # helper used by this page
        └── sync-log/
            └── page.tsx
```

The folder name is the page's slug, and the slug is the last segment of its URL:

```text theme={"system"}
https://app.attio.com/{workspaceSlug}/apps/{appSlug}/{pageSlug}
```

So `src/app/pages/dashboard/page.tsx` is served at `/{workspaceSlug}/apps/{appSlug}/dashboard`.

### Discovery rules

* Page folders sit directly inside `src/app/pages/`. Pages do not nest: `src/app/pages/reports/weekly/page.tsx` is a build error.
* Folder names follow the same format as extension ids: lowercase kebab-case, starting with a letter, containing only lowercase letters, digits and single hyphens, at most 64 characters.
* Each folder contains exactly one definition file, `page.tsx` or `page.ts`. Other files in the folder are ignored by discovery; import them from `page.tsx` like any other module.
* The `definePage(...)` call must be the file's default export directly.

Pages are the one entry point not discovered through `extension.tsx`. Everything else about [app structure](../extensions/overview) still applies.

## Example

```tsx src/app/pages/dashboard/page.tsx theme={"system"}
import React from "react"
import {Extensions, Grid, Card, Typography} from "attio/client"

import {PipelineChart} from "./pipeline-chart"

export default Extensions.definePage({
  name: "Dashboard",
  Page: () => (
    <Grid maxColumns={3}>
      <Card title="Open deals">
        <Typography.Title>42</Typography.Title>
      </Card>
      <Card title="Pipeline">
        <PipelineChart />
      </Card>
    </Grid>
  ),
})
```

## Sidebar

Once a workspace installs an app with at least one page, the app appears in the Apps section of the sidebar. Clicking the app row opens its first page, where pages are ordered alphabetically by slug. Apps with more than one page expand to list them. Apps without pages get no sidebar entry.

## Loading

`Page` can suspend. While it does, Attio shows the page skeleton with the real header already in place: the name comes from your page definition, so it renders before your code has booted. Add your own `React.Suspense` boundaries inside the page when one slow section shouldn't hold up the rest.

## Errors

If `Page` throws, Attio renders an error state in place of that page. Nothing else about your app is affected: record actions, widgets, other pages and tabs keep working.

## Build errors

The CLI checks pages on every `attio dev` and `attio build`. The build fails when:

* A folder contains both `page.ts` and `page.tsx`. Keep exactly one.
* A `page.tsx` sits directly in `src/app/pages/` rather than in a subfolder.
* A folder name is not a valid slug (see the format above).
* A `page.tsx` is nested more than one folder deep.
* The file doesn't default-export an `Extensions.definePage()` call.
