# What QUESTPIE is (/docs/learn)

---
title: What QUESTPIE is
description: You describe a table once. QUESTPIE derives the database schema, a typed API and a client from that description, and modules add the admin and the machine-readable surfaces on top.
kind: learn
package: questpie
---

This page walks you through one collection file, what the core builds from it,
what the modules add, and which package each piece comes from. You do not have to
install anything to follow along.

## Defining a collection

A **collection** is one database table plus the rules around it. You define it in
a file, and the filename is the registration. There is nothing to import into a
central config.

To define a collection, create a file in `src/questpie/server/collections/` and
export a `collection()` call. For example, to define a `news` table:

```ts title="src/questpie/server/collections/news.ts"
import { collection } from "#questpie/factories";

export const news = collection("news")
	.fields(({ f }) => ({
		title: f.text(255).label("Title").required(),
		content: f.textarea(),
		isPublished: f.boolean().default(false),
	}))
	.title(({ f }) => f.title);
```

Three fields, and a `.title()` that tells the admin which field to show as the
label of a row. That is the whole definition.

## What the core gives you

To build everything from that file, run the generator:

```bash
questpie generate
```

Three things now exist that you did not write. All three come from `questpie`
itself, with no module to enable.

### A typed object

`app.collections.news` carries the field names you declared:

```ts
const { docs } = await app.collections.news.create({
	title: "Hello",
	isPublished: true,
});
```

Misspell one and the code does not compile, so it never reaches the database:

```ts
// [!code word:titel]
await app.collections.news.create({ titel: "Hello" }); // [!code error]

// TS2561: Object literal may only specify known properties,
// but 'titel' does not exist in type '...'.
// Did you mean to write 'title'?
```

Rename `title` in the collection file and this breaks in your editor the moment
you run the generator, instead of failing for a user later.

### Five REST routes

Every collection gets the same five, named after it:

```bash
GET    /api/news
GET    /api/news/:id
POST   /api/news
PATCH  /api/news/:id
DELETE /api/news/:id
```

### A typed client

The same calls in your frontend, carrying the types the server has:

```ts
const { docs } = await client.collections.news.find({
	where: { isPublished: true },
});
```

<Callout type="info" title="Change the definition, and all three follow">
	Change `f.text(255)` to `f.text(500)` and run the generator again. The column,
	the routes and the client types all move together. Nothing is defined twice,
	so nothing can drift.
</Callout>

## What the modules add

The admin screen and the machine-readable surfaces are **modules**, not core. You
enable them, and each one is a package you can read and replace.

### The admin, from `@questpie/admin`

A list that uses your labels, and a form that picks each control from the field
type. `text` gets an input, `textarea` gets a multi-line box, `boolean` gets a
switch.

The module also contributes two field types of its own, so they appear on `f`
only when it is enabled: `richText` for a WYSIWYG document, and `blocks` for
stacked content.

It is generic over your schema rather than built for one kind of content. Its job
is to let the people who own the data work with it in a normal interface, instead
of opening a database client or keeping the real numbers in a spreadsheet.

Where a collection has a `blocks` field, that includes a visual canvas for
stacking and nesting content, and live preview streamed into your own frontend.
QUESTPIE never renders your site. Your app renders it, and the admin sends it
patches as the editor types.

<Callout type="warn" title="The admin needs a runtime that renders">
	`create-questpie` turns it on by default for TanStack Start and Next. Hono and
	Elysia are headless, so the module is rejected there and the project is API
	plus typed client only.
</Callout>

### OpenAPI, from `@questpie/openapi`

An OpenAPI document for the same routes, and a Scalar reference UI at
`/api/docs`. On by default for all four runtimes.

### MCP, from `@questpie/mcp`

The same app as a Model Context Protocol server, so an AI agent can call it under
the access rules you already wrote rather than a second set.

## The ecosystem

Every package does one job, and the seams are where you would expect them.

| Package                              | What it is for                                                                             |
| ------------------------------------ | ------------------------------------------------------------------------------------------ |
| `questpie`                           | The core. Collections, globals, fields, hooks, jobs, access rules, REST, the typed client. |
| `create-questpie`                    | Scaffolds a project and picks the runtime and modules for you.                             |
| `@questpie/admin`                    | The generated data workspace.                                                              |
| `@questpie/openapi`                  | OpenAPI document and Scalar reference UI.                                                  |
| `@questpie/mcp`                      | MCP server, under the app's own access rules.                                              |
| `@questpie/hono` · `elysia` · `next` | Runtime adapters. TanStack Start ships as a template rather than an adapter.               |
| `@questpie/tanstack-query`           | Typed query-options factory for the client.                                                |
| `@questpie/tanstack-db`              | Typed TanStack DB collections backed by the client.                                        |
| `@questpie/workflows`                | Durable, replay-based workflow engine.                                                     |
| `@questpie/crdt-yjs`                 | Yjs text engines for collaborative documents.                                              |
| `@questpie/sandbox`                  | Hardened isolated execution for untrusted scripts.                                         |
| `@questpie/observability`            | OpenTelemetry traces and metrics over OTLP.                                                |

## What you still write yourself

QUESTPIE derives the plumbing around your data. It does not write your product.

- **Your pages.** You get a typed client, not a frontend.
- **Your business rules.** You declare who may read what. What "published" means
  for your company is code you write.
- **Anything with an opinion.** Pricing, workflows, the words on your buttons.

## What it runs on

| Requirement | Version | Why                                                   |
| ----------- | ------- | ----------------------------------------------------- |
| Bun         | 1.3+    | The runtime the starter template targets.             |
| PostgreSQL  | 15+     | The minimum database version QUESTPIE supports.       |
| Licence     | MIT     | Your servers. There is no hosted tier to graduate to. |

## Next

**[The one-schema model](/docs/learn/one-schema)** goes one level down: what a
declaration is, what the generator writes, and when you have to run it again.
