# Admin (/docs/admin)

---
title: Admin
description: The admin is a data workspace generated from your schema. The people who own the data get a real interface, instead of a database client or a spreadsheet that drifts.
kind: guide
package: "@questpie/admin"
---

The admin is generic over your schema. It is not built for blog posts, or for
products, or for any one kind of content. It reads what you declared and renders
that. Add a field and it turns up in the form on the next generate. Nobody keeps
a second copy of your model in a React app.

This group covers how far you can move it, and where the built-in behaviour
stops.

## Turn it on

The admin is a module with two halves. Register each one.

```ts title="src/questpie/server/modules.ts"
import { adminModule } from "@questpie/admin/modules/admin";

export default [adminModule] as const;
```

```ts title="src/questpie/admin/modules.ts"
import { adminClientModule } from "@questpie/admin/client/modules/admin";

export default [adminClientModule] as const;
```

```bash
questpie generate
```

The server half contributes collections, routes, views, components and two field
types, `f.richText()` and `f.blocks()`. The client half turns the server's
references into React screens. Generate writes
`src/questpie/admin/.generated/client.ts`, and your `/admin` route mounts it.
`create-questpie` writes all of this for you.

`adminModule` also pulls in `starterModule`. That is where the Better Auth tables
and the `assets` upload collection come from. A fresh panel has users and a media
library on day one.

<Callout type="warn" title="Two runtimes, not four">
	The admin needs a render layer. `create-questpie` turns it on by default for
	TanStack Start and Next, and rejects it on Hono and Elysia. Those two stop at
	the API and the typed client.
</Callout>

## What you get before you configure anything

| URL                               | What is there                                       |
| --------------------------------- | --------------------------------------------------- |
| `/admin`                          | The dashboard                                       |
| `/admin/collections/posts`        | The list, with filters, sorting and a column picker |
| `/admin/collections/posts/create` | An empty form                                       |
| `/admin/collections/posts/:id`    | That row's form                                     |
| `/admin/globals/siteSettings`     | The one row a global holds                          |
| `/admin/login`                    | Sign in                                             |
| `/admin/setup`                    | Creates the first admin, while none exists          |

The URL uses the registered name, not the file name. So `collection("blog-posts")`
sits at `/admin/collections/blogPosts`.

A form with no form config generates its fields from the collection. A list with
no list config picks its own columns. The title first, then up to six short
fields, then `createdAt`. Relations, uploads, rich text, JSON, objects, arrays
and textareas stay out of that default, because they are wide or expensive to
load. Every one of them is still in the column picker.

## Who may sign in

One rule decides it. `session.user.role === "admin"`. A signed-in user without
that role is not an admin user, and every admin RPC route refuses them.

Read access filters the rest. A collection your session cannot read is missing
from the config the client receives, so it is missing from the sidebar too.

The first admin is a chicken-and-egg problem. `/admin/login` asks the server
whether any user holds the admin role. If none does, it sends you to
`/admin/setup`, which creates one. Once one exists, setup refuses to create any
more.

## Where each topic lives

| Topic                                             | Page                                               |
| ------------------------------------------------- | -------------------------------------------------- |
| Labels, icons, list columns, form layout, actions | [Collections and globals](/docs/admin/collections) |
| Sidebar, dashboard, branding, theming, mounting   | [Configuration](/docs/admin/configuration)         |
| Your own views, widgets, pages and blocks         | [Custom views](/docs/admin/custom-views)           |
| Better Auth, roles, setup and invitations         | [Authentication](/docs/admin/auth)                 |
| Who changed what, and when                        | [Audit](/docs/admin/audit)                         |
| Stacked content a person arranges                 | [Blocks](/docs/schema/blocks)                      |
| How a module contributes all of the above         | [Modules](/docs/code/modules)                      |

## Next

**[Collections and globals](/docs/admin/collections)** is the page to read first.
It covers `.admin()`, `.list()`, `.form()`, `.preview()` and `.actions()`, the
five methods `@questpie/admin` adds to a collection.
