QUESTPIE
Start Here

What is QUESTPIE

A backend-first TypeScript framework where schema drives everything — from database to typed frontends.

QUESTPIE is a backend-first TypeScript framework. You define your data schema once, codegen generates the typed runtime, and any frontend can consume it through introspection.

It is not a CMS. The admin panel is one projection of your schema — the same way an SDK, an OpenAPI spec, or a mobile app would be. The framework exists independently of any UI.

The Core Idea

Schema Definition → Codegen → Typed Runtime → Projection → Frontend(s)

                              Database tables
                              API validation
                              Query operators
                              Type inference

You write a collection file. Codegen reads it and generates:

  1. Database schema — Drizzle ORM table definitions
  2. API layer — CRUD endpoints with Zod validation
  3. Type exports - AppConfig, AppCollections, AppRoutes for end-to-end type safety
  4. Module augmentationAppContext with typed collections, queue, email, and any custom services

The admin panel, client SDK, and OpenAPI spec all consume these generated types. Nothing is defined twice.

Mental Model

Think of QUESTPIE in three layers:

Layer 1: Schema (you write this)

collections/posts.ts
import { collection } from "#questpie/factories";

export default collection("posts").fields(({ f }) => ({
	title: f.text().required(),
	body: f.textarea(),
	status: f.select(["draft", "published"]),
}));

Layer 2: Codegen (automatic)

Running questpie generate discovers your files and generates:

  • Type-safe app instance with all collections, routes, jobs, services
  • AppContext module augmentation so every handler gets typed DI
  • AppConfig type for the client SDK

Layer 3: Projection (consumers)

Client SDK
const posts = await client.collections.posts.find({
	where: { status: "published" },
	orderBy: { createdAt: "desc" },
});
// posts is fully typed from your schema
Admin Panel
// Reads the same schema via introspection
// Generates list views, form fields, filters automatically

Why Not Just Use [X]?

If you need...QUESTPIE gives you...
A typed API from schemaCollections → CRUD endpoints + Zod validation + query operators
Business logic alongside dataRoutes, hooks, jobs - all in the same project with DI
An admin panel@questpie/admin reads your schema, no separate config
Multiple frontendsOne schema, typed client SDK for any framework
Full-stack type safetySchema types flow from server → codegen → client

Context-First Architecture

Every handler in QUESTPIE receives its dependencies through context — no imports, no singletons, no god objects:

routes/create-booking.ts
import { route } from "questpie";
import z from "zod";

export default route()
	.post()
	.schema(
		z.object({
			barberId: z.string(),
			serviceId: z.string(),
			scheduledAt: z.string().datetime(),
		}),
	)
	.handler(async ({ input, collections, queue }) => {
		const service = await collections.services.findOne({
			where: { id: input.serviceId },
		});

		const appointment = await collections.appointments.create({
			barber: input.barberId,
			service: input.serviceId,
			scheduledAt: new Date(input.scheduledAt),
			status: "pending",
		});

		await queue.sendAppointmentConfirmation.publish({
			appointmentId: appointment.id,
		});

		return { success: true, appointmentId: appointment.id };
	});

collections, queue, email, db, session — all injected through AppContext. Codegen generates the type augmentation, so everything is discoverable and typed.

What's Next

On this page