Project Structure
VexCMS is a pnpm + Turborepo monorepo. Three kinds of directory live in it, and each means something specific.
Packages, apps, and templates
Section titled “Packages, apps, and templates”A package (packages/*) is a published @vexcms/* npm package (or
create-vexcms) — framework-agnostic library code with its own
package.json#exports map, built with tsup, versioned with Changesets.
Packages never read environment variables or assume a particular host
framework; @vexcms/next is the one exception that is itself a framework
adapter, not a host.
An app (apps/*) is a real, deployed Next.js application that consumes
the published package surface — apps/test (the dogfood/admin host used for
day-to-day development, port 3020) and apps/docs (this Astro +
Starlight site, port 4321). Apps import @vexcms/* packages exactly the way
a user’s own app would; there is no special internal-only import path.
A template (packages/create-vexcms/templates/*) is a scaffold a user’s
project is generated from by pnpm create vexcms — base-nextjs (minimal
Next.js + auth + one collection) and marketing-site (the richer app
mirrored from apps/www’s own source, including its full block library).
Templates are hand-maintained copies kept in sync with the apps they’re
derived from, not generated — there is no extraction/codegen layer between
an app and its template.
Dependency diagram
Section titled “Dependency diagram”@vexcms/core │ ▼@vexcms/react │ ▼@vexcms/next ──┐ │ (peers of core/react, not of each other)@vexcms/richtext-plate@vexcms/better-auth@vexcms/file-storage-convex
@vexcms/cli ───▶ scaffolds via create-vexcms
apps/test, apps/www ───▶ consume the published surface like any user appcore→react:@vexcms/reactis framework-agnostic admin UI built on top of@vexcms/core’s schema/field/RBAC primitives. Core has zero React/JSX imports (seehkt-adapter-architecture.md).react→next:@vexcms/nextis the Next.js adapter — it wraps@vexcms/react’s admin panel inNextAdminPage/NextAdminLayoutand adds Next-specific cache/SEO helpers. It never flows back intoreactorcore.richtext-plate/better-auth/file-storage-convexas peers: each is an optional adapter a project opts into fromcore/react— a richtext editor adapter, an auth adapter, and a file-storage adapter, respectively. None of the three import each other.cliscaffoldscreate-vexcms:@vexcms/cliships thevexdev/ build/generate commands a scaffolded project runs;create-vexcmsis the separatepnpm create vexcmspackage that generates a new project (which then depends on@vexcms/cliitself, not the other way around).apps/testandapps/wwwconsume the published surface the same way a user’s app would — through packageexportsentries, never through relative imports into a package’ssrc/.
Entry points
Section titled “Entry points”Every package’s public surface is its package.json#exports map — each key
is one import specifier, and each one exists because it serves a different
runtime boundary (server-only code, client-only code, styles, test helpers).
| Package | Entry | What it’s for |
|---|---|---|
| @vexcms/core | . | Field builders, defineConfig/defineCollection/defineGlobal/defineAccess, type-generation utilities — imported by both server and client code. |
| | ./server | Server-only Convex query/mutation API (vexServerApi, createVexCallbackApi, vexConvexApi) — imported from Convex function files only. |
| | ./internal | Internal-only helpers shared across @vexcms/* packages; not part of the public contract. |
| @vexcms/react | . | Admin UI components, hooks, and the React-typed config builders re-exported from core. |
| | ./client | Client-safe query/mutation API (find/get/search/create/update/remove factories) wired to TanStack Query. |
| | ./form | The exported app form (useAppForm, AppForm, FormFieldLayout, the leaf *Field components) — the public, framework-only form layer a project can build custom UI on, independent of the admin panel. |
| | ./styles | The admin UI’s Tailwind stylesheet. |
| | ./testing | Shared test suites/fixtures (fieldInputContract, mediaSuite, …) packages and apps reuse to test their own field/component overrides. |
| @vexcms/next | . | Re-exports of core/react config builders, sized for a single Next.js import. |
| | ./server | NextAdminPage — the async server component rendering the whole admin panel. |
| | ./client | NextAdminLayout/NextAdminLayoutClient — the client-side layout wrapper. |
| | ./cache | Server-only createVexServerClient/createVexRevalidateRoute for server actions and ISR routes. |
| | ./seo | Server-only vexStaticParams/vexMetadata/createVexSitemap/createVexRobots. |
| | ./testing | Next-specific test utilities. |
| @vexcms/better-auth | . | betterAuthAdapter, Convex DB wiring (authDbApi, createBetterAuthAdapter), createGetAuth — server-only, reads secrets. |
| | ./client | betterAuthCollections — the schema-descriptor resolver vex.config.ts uses to derive auth collections browser-safely. |
| @vexcms/file-storage-convex | . | convexFileStorage adapter + defineMediaCollection — server-side storage wiring. |
| | ./client | Client-safe upload helpers only. |
| @vexcms/richtext-plate | . | plateEditor() editor-adapter factory, the RichText render component, shared element types; also serves a convex condition pointing at ./dist/server.js for Convex bundler builds. |
| | ./editor | The interactive PlateEditorField + plugin/feature setup for the admin panel. |
| | ./render | RichText + getStaticComponents for building a custom static renderer. |
| @vexcms/cli | . | The vex CLI binary (dev/deploy/generate). |
| create-vexcms | . | The pnpm create vexcms scaffolder binary — not a library import. |
See Package Layout for what lives inside each
package’s src/.