Features
Everything the schema already knows.
Field types, uploads, and relations come from defineCollection. The CMS, the API, and TypeScript all read the same file.
From schema
Code generates the content model.
The CMS is not configured separately. Field types, relations, and media come from the same defineCollection call your app already compiles.
Hover a field in the schema and it lights up in the generated document. That mapping is the product: what you type is what editors get, and what your loaders return.
Add a field, change a type, or point a relation at another collection. The admin updates with the next boot — no dashboard export, no generated config to check in.
- Code
- Generates
- Content model
collections.ts
cms / collections / posts
Document
Stackpress infers a typed client from the same collection you edit.
cover-hero.jpg
image/jpeg · 248 KB
Types
One schema. End-to-end types.
The client you call from loaders is inferred from the same collection definition. Populate expands uploads and relations without losing TypeScript.
find and getGlobal know your collections. Where clauses, populate lists, and returned documents are checked against the schema — not against a hand-written DTO.
Populate is not a type hole. An upload becomes a media document with a URL. A relation becomes the related document. The inferred Post type follows.
- Schema
- CMS
- API
- Application
routes/posts.$slug.tsx
Post
inferred- title: string
- content: RichText
- cover: Media
- author: Author
Media
Media that fits your stack.
Upload files, store metadata on a media collection, and serve them through your storage adapter — S3-compatible, or anything that implements the adapter.
Files are first-class: filename, alt, MIME, size, and the adapter that stored them. The CMS media library is that collection, not a sidecar product.
Your app serves files through a proxied route such as /cms/file/:id. Swap S3 for another adapter without changing how documents reference uploads.
- Upload
- Metadata
- Storage adapter
- File URL
cms / media
Relations
Content that knows its neighbors.
Relations are fields in the schema, not a separate graph product. Populate them in a query and TypeScript follows.
An author on a post is { type: 'relation', to: 'authors' }. Editors pick a document. Query code populates it. The type of post.author is Author.
There is no join DSL to learn beside the schema. If the field exists, you can populate it. If it does not, TypeScript will not let you pretend.
Content infrastructure, without the abstraction tax.
Define your model in TypeScript. Give your team a powerful editing experience. Ship typed content wherever you need it.
Open the CMS