QUESTPIE
Start Here

Project Structure

File convention layout, discovery rules, and generated output.

QUESTPIE uses a file convention — your project structure determines what gets discovered and wired into the runtime. No manual registration required.

Standard Layout

my-app/
├── questpie.config.ts                    # CLI config (re-exports server config)
├── src/
│   ├── questpie/
│   │   ├── server/
│   │   │   ├── questpie.config.ts        # Runtime config (DB, plugins, adapters)
│   │   │   ├── modules.ts                # Module dependencies
│   │   │   ├── auth.ts                   # Authentication config
│   │   │   ├── locale.ts                 # Content locale config
│   │   │   │
│   │   │   ├── collections/              # One file per collection
│   │   │   │   ├── posts.ts
│   │   │   │   ├── categories.ts
│   │   │   │   └── comments.ts
│   │   │   │
│   │   │   ├── globals/                  # One file per global
│   │   │   │   └── site-settings.ts
│   │   │   │
│   │   │   ├── routes/                   # App routes (JSON or raw)
│   │   │   │   ├── create-booking.ts
│   │   │   │   └── get-stats.ts
│   │   │   │
│   │   │   ├── jobs/                     # Background tasks
│   │   │   │   └── send-email.ts
│   │   │   │
│   │   │   ├── services/                 # Singleton services
│   │   │   │   └── blog.ts
│   │   │   │
│   │   │   ├── blocks/                   # Content blocks (admin plugin)
│   │   │   │   ├── hero.ts
│   │   │   │   └── gallery.ts
│   │   │   │
│   │   │   ├── emails/                   # Email templates
│   │   │   │   └── appointment-confirmation.ts
│   │   │   │
│   │   │   ├── config/                   # Typed configuration files
│   │   │   │   ├── auth.ts              # Auth config (Better Auth)
│   │   │   │   ├── app.ts              # App config (locale, access, hooks)
│   │   │   │   ├── admin.ts            # Admin config (sidebar, dashboard, branding)
│   │   │   │   └── openapi.ts          # OpenAPI config
│   │   │   │
│   │   │   └── .generated/               # Codegen output (never edit)
│   │   │       ├── index.ts              # App instance + types
│   │   │       └── module.ts             # Merged module
│   │   │
│   │   └── admin/                        # Admin client customizations
│   │       ├── admin.ts                  # Re-exports generated admin config
│   │       ├── hooks.ts                  # Typed React hooks
│   │       ├── .generated/               # Codegen output (never edit)
│   │       │   └── client.ts             # Admin client config
│   │       └── blocks/                   # Block renderers (React)
│   │           ├── hero.tsx
│   │           └── gallery.tsx
│   │
│   ├── lib/
│   │   └── client.ts                     # Client SDK setup
│   │
│   └── routes/                           # App routes (framework-specific)
│       └── api/
│           └── $.ts                      # API catch-all handler

Discovery Rules

Codegen discovers files based on directory name and export pattern:

DirectoryExportKey derivationExample
collections/Default or namedFilename → camelCaseblog-posts.tsblogPosts
globals/Default or namedFilename → camelCasesite-settings.tssiteSettings
routes/DefaultFilename → camelCase/slash pathcreate-booking.tscreateBooking
jobs/DefaultFilename → camelCasesend-email.tssendEmail
routes/ (raw)DefaultFilename → slash pathwebhook.tswebhook
services/DefaultFilename → camelCaseblog.tsblog
blocks/Named exportsExport nameexport const herohero
emails/DefaultFilename → camelCaseappointment-confirmation.tsappointmentConfirmation

Single-file conventions

Some configs are single files instead of directories:

FilePurpose
questpie.config.tsRuntime config (DB, plugins, adapters)
modules.tsModule dependencies array
config/auth.tsAuth config via authConfig() (Better Auth options)
config/app.tsApp config via appConfig() (locale, access, hooks)
config/admin.tsAdmin config via adminConfig() (sidebar, dashboard, branding)
config/openapi.tsOpenAPI config via openApiConfig() (spec info, Scalar)

Nested routes

Routes support nested directories for namespacing:

routes/
├── booking/
│   ├── create.ts          → client.routes.booking.create()
│   └── cancel.ts          → client.routes.booking.cancel()
├── get-stats.ts           → client.routes.getStats()

The .generated/ Directory

Running bunx questpie generate creates .generated/ with:

index.ts — App instance and types

// Auto-generated — do not edit
import type { AppCollections, AppGlobals, AppRoutes, AppJobs } from "./module";

export type AppConfig = {
	collections: AppCollections;
	globals: AppGlobals;
	routes: AppRoutes;
	// ... auth, locales
};

export { app, createContext } from "./app";
export type { AppConfig, AppCollections, AppGlobals, AppRoutes, AppJobs };

Module augmentation

The generated code augments AppContext so every handler gets typed DI:

declare global {
	namespace Questpie {
		interface AppContext {
			db: Database;
			email: MailerService<AppEmailTemplates>;
			queue: QueueClient<AppJobs>;
			collections: AppCollections;
			globals: AppGlobals;
			session: Session | null;
			// ... custom services
		}
	}
}

This is why collections, queue, email are available and typed in every handler — codegen generates the augmentation from your file structure.

The #questpie Imports

QUESTPIE uses Node.js subpath imports (the "imports" field in package.json) to wire your code to the generated output:

ImportResolves toUse for
#questpie.generated/index.tsapp instance, AppConfig type
#questpie/factories.generated/factories.tscollection(), global(), sidebar(), etc.

Collection, global, and admin singleton files import from #questpie/factories:

import { collection } from "#questpie/factories";

The generated factories file provides typed builders with all plugin extensions (e.g. .admin(), .form(), .list()) and the merged field set (builtins + module-contributed fields like richText, blocks).

Routes, jobs, and seeds import from the bare questpie package:

import { route } from "questpie";
import { job } from "questpie";
import { seed } from "questpie";

By-Feature Layout

For larger projects, you can organize by feature instead of by type:

src/questpie/server/
├── features/
│   ├── blog/
│   │   ├── collections/
│   │   │   └── posts.ts
│   │   ├── routes/
│   │   │   └── publish.ts
│   │   └── jobs/
│   │       └── notify-subscribers.ts
│   └── booking/
│       ├── collections/
│       │   └── appointments.ts
│       └── routes/
│           └── create-booking.ts
├── questpie.config.ts
└── modules.ts

Both layouts can coexist. Codegen scans all configured paths.

What's Next

On this page