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

# Pages

> Guide to your Inertia data model

When building applications using Inertia, each page in your application typically has its own controller / route and a corresponding JavaScript component.
This allows you to retrieve just the data necessary for that page - no API required. With `inertia-server`, working with pages is based on the concept
of page definitions created by the `definePage` function.

```ts theme={null}
const { definePage } = createInertia(...);
```

## Creating page definitions

Page definitions consist of the component name, and a set of props that will be passed to it.

```ts ~/server/inertia.ts theme={null}
import { createInertia, prop, mergedProp, deepMergedProp, type PageProps } from 'inertia-server';

const homePage = definePage({
  component: 'Home',
  props: {
    title: prop<string>(),
    description: prop<string>(),
    posts: mergedProp<Posts[]>(),
    tasks: deepMergedProp<Tasks[]>().deferred(),
  },
  // Make sure that the 'user' shared key is available
  // during render, otherwise it is optional
  requireShared: ['user'],
});

export type HomePageProps = PageProps<typeof homePage>;
```

When handling inertia requests, you can render your page by passing a page context
to the `render` function. It is created by invoking your page definition with the required props.

```typescript theme={null}
inertia.render(homePage({
  title: 'Welcome',
  description: 'Hello, World!',
  posts: () => getPosts(req.params.page),
  tasks: () => getTasks(),
}));
```

On the client, you can use the created definitions to access your data with full type safety.

<CodeGroup>
  ```tsx react icon="react" theme={null}
  import type { HomePageProps } from '~/server/inertia';

  function Home({ user, posts, tasks }: HomePageProps) {
    /**
     * interface Props {
     *  title: string;
     *  description: string;
     *  posts: Posts[];
     *  tasks?: Tasks[];
     *  user: User
     * }
    */
    const { title, description, posts, tasks } = props;
    return (
      <div>
        <h1>{title}</h1>
        <p>Hello, {user.name}! {description}</p>
        <ul>
          {posts.map((post) => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
        {tasks ? (
          <ul>
            {tasks.map((task) => (
              <li key={task.id}>{task.title}</li>
            ))}
          </ul>
        ) : "Loading tasks..."}
      </div>
    );
  }
  ```

  ```svelte svelte icon="https://mintcdn.com/inertiaserver/HnDNLZ7246yQpG3Y/assets/icons/svelte.svg?fit=max&auto=format&n=HnDNLZ7246yQpG3Y&q=85&s=447d2e650742154c2931d6321707e2ed" theme={null}
  <script>
    import type { HomePageParams } from '~/server/inertia';

    /**
     * interface Props {
     *  title: string;
     *  description: string;
     *  posts: Posts[];
     *  tasks?: Tasks[];
     *  user: User
     * }
    */
    let { title, posts, tasks, user } = $props<HomePageProps>();
  </script>

  <div>
    <h1>{title}</h1>
    <p>Hello, {user.name}! {description}</p>
    <ul>
      {#each posts as post}
        <li key={post.id}>{post.title}</li>
      {/each}
    </ul>
    {#if tasks}
      {#each tasks as task}
        <li key={task.id}>{task.title}</li>
      {/each}
    {:else}
      <p>Loading tasks...</p>
    {/if}
  </div>
  ```
</CodeGroup>

## Data & Props

Page props builders - `prop`, `mergedProp`, `deepMergedProp` provide various chained methods
to help you customize your data loading behavior.

### Merging props

Inertia overwrites props with the same name when reloading a page. However, you may need to merge new data with existing data instead.
For example, when implementing a “load more” button for paginated results.

Prop merging only works during [partial](https://inertiajs.com/docs/v2/data-props/partial-reloads) reloads. Full page reloads
will override the props with the new values.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    posts: mergedProp<Posts[]>(),
  },
});
```

<Expandable title="Usage">
  ```ts theme={null}
  inertia.render(
    page({
      posts: () => [
        { id: 1 },
        { id: 2 },
      ],
    })
  );

  inertia.render(
    page({
      posts: () => [
        { id: 3 },
        { id: 4 },
      ],
    })
  );

  const finalPostsProp = [
    { id: 1 },
    { id: 2 },
    { id: 3 },
    { id: 4 },
  ];
  ```
</Expandable>

By default, new data will be appended to the end of the existing data. You can change this behavior by chaining the `prepend` method.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    posts: mergedProp<{ id: number }[]>().prepend(),
  },
});
```

<Expandable title="Usage">
  ```ts theme={null}
  inertia.render(
    page({
      posts: () => [
        { id: 1 },
        { id: 2 },
      ],
    })
  );

  inertia.render(
    page({
      posts: () => [
        { id: 3 },
        { id: 4 },
      ],
    })
  );

  const finalPostsProp = [
    { id: 3 },
    { id: 4 },
    { id: 1 },
    { id: 2 },
  ];
  ```
</Expandable>

If you want to not only append, but replace some of the existing data, provide a `matchOn` option.
By sending items with the same key, elements will be replaced, and rest - appended or prepended.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    posts: mergedProp<{ id: number, value: string }[]>({ matchOn: "id" }),
  },
});
```

<Expandable title="Usage">
  ```ts theme={null}
  inertia.render(
    page({
      posts: () => [
        { id: 1, value: 'foo' },
        { id: 2, value: 'bar' },
      ],
    })
  );

  inertia.render(
    page({
      posts: () => [
        { id: 1, value: 'baz' },
        { id: 2, value: 'qux' },
      ],
    })
  );

  const finalPostsProp = [
    { id: 1, value: 'baz' },
    { id: 2, value: 'qux' },
  ];
  ```
</Expandable>

### Deep merging

Instead of specifying which nested paths should be merged, you may use `deepMergedProp` to ensure a deep merge of the entire structure.

```ts theme={null}
const page = definePage({
  component: 'Chat',
  props: {
    chat: deepMergedProp<{ 
      messages: { id: number; text: string }[], 
      online: 12
    }>({ matchOn: "meesges.id" }),
  },
});
```

<Expandable title="Usage">
  ```ts theme={null}
  inertia.render(
    page({
      chat: () => {
        return { messages: [{ id: 1, text: 'Hello' }], online: 12 };
      },
    })
  );

  inertia.render(
    page({
      chat: () => {
        return { messages: [{ id: 2, text: 'World' }], online: 13 };
      },
    })
  );

  const finalChatProp = {
    messages: [
      { id: 1, text: 'Hello' },
      { id: 2, text: 'World' },
    ],
    online: 13,
  };
  ```
</Expandable>

<Note>
  Deep merging was introduced before normal merging had support for prepending and targeting nested paths. In most cases, `mergedProp()`
  with `matchOn` and its `append` and `prepend` methods should be sufficient.
</Note>

### Infinite scrolling

Merged props can be used to implement [infinite scrolling](https://inertiajs.com/docs/v2/data-props/infinite-scroll) with inertia `<InfiniteScroll>` component.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    posts: mergedProp<Posts[]>().scroll(),
  },
});
```

In this case, inertia will try to read `page` query parameter from your request and use it as the page number. To customise it, you can use the `pageName` option.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    posts: mergedProp<Posts[]>().scroll({ pageName: 'page' }),
  },
});
```

When rendering a page, inertia will require you to provide the `hasMore` prop. It will be used to determine if there is more data to load.

```ts theme={null}
inertia.render(page({
  posts: () => getPosts(page),
  otherScrollProp: () => getOtherScrollProp(page),
  $hasMore: {
    posts: true,
    otherScrollProp: true,
  },
}));
```

To make backend integration easier, you can read the page parameter name from the page definition.

```ts theme={null}
function handler(req: Request) {
  const pageQueryParam = postsPage.scrollOptions.posts.pageName;
  const page = req.query[pageQueryParam];
}
```

### Lazy loading

When rendering a page, every `prop` value can be a literal, or a lazy evaluated function.
It's up to you which data loading strategy to use. Let's see how it works on an example.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    foo: prop<string>(),
    bar: prop<string>().deferred(),
  },
})

// Option 1
inertia.render(page({
  foo: 'foo',
  bar: () => getBar(),
}));

// Option 2
inertia.render(page({
  foo: () => 'foo',
  bar: getBar(),
}));
```

In both cases, the `foo` prop will be sent during every page request, but if you define
its value as a function, it will be resolved when inertia needs to parse its value,
not at the moment of the `render` call. It is especially useful when you work with partial
data requests.

Interestingly, the `bar` prop will not be parsed by inertia on the first request. By default
you should provide a lazy evaluable function to defer execution of your code until it's needed.
But if you want to, you can provide a literal value at the moment of the `render` call. It will
not be sent to the client, but it may useful if you want to execute some side effect when a page
is rendered and the prop prepared, no matter whether its loaded or not.

### Deferred props

To defer a prop, you can use the `deferred()` method on the prop definition.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    foo: prop<string>().deferred(),
  },
});
```

By default, all deferred props get fetched in one request after the initial page is rendered, but you can choose to fetch data in parallel by grouping props together.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    permissions: prop<string[]>().deferred(),
    teams: prop<string[]>().deferred('attributes'),
    roles: prop<string[]>().deferred('attributes'),
  },
});
```

In the example above, the `teams` and `roles` props will be fetched in one request, while the permissions prop will be fetched in a separate request in parallel. Group names are arbitrary strings and can be anything you choose.

On the client side, inertia provides the `Deferred` component to handle deferred props. It is not required with `inertia-server`, because we correctly type deferred props as optional, so you can
just check for the value and show a loading state. If you need to
differentiate between the loading state and a potential empty value, use the component though.

### Prop modifiers

When Inertia performs a request, it will determine which data is required and only then will it evaluate the closure. With prop modifiers, you can manually control this behavior.

Use `optional()` method to specify that a prop should never be included unless explicitly requested using the `only` client option.

On the reverse, you can use `always()` method to specify that a prop should always be included, even in partial reloads.

To load a prop on the first request, and then to keep it in the cache, you can use `once()` method.

```ts theme={null}
const page = definePage({
  component: 'Home',
  props: {
    foo: prop<string>().optional(),
    bar: prop<string>().always(),
    baz: prop<string>().once(),
  },
});
```

## Accessing other page object properties

Flash data and errors are available inside the props object. To access page url, version and other metadata, use hooks from your framework of choice.

```tsx react icon="react" theme={null}
import { usePage } from '@inertiajs/react';
const { url, version } = usePage();

return (
  <div>
    <h1>{url}</h1>
    <p>{version}</p>
  </div>
);
```
