Introduction
Declare a content type once in TypeScript and the VitNode Content Engine generates its Postgres table, validation, staff API, permissions and AdminCP screens.
The Content Engine turns one TypeScript definition into structured content for your plugin. You describe the fields of an article or a category, and VitNode generates the database table, Zod validation, staff-only API routes, staff permissions and AdminCP screens. Optional blocks add drafts, a public API, pages with SEO metadata, revisions, scheduling, live editing, translations and search.
This is the whole definition behind the example plugin's Categories screen:
import { defineContentType, field } from "@vitnode/core/content";
export const categoryContentType = defineContentType({
id: "example.category",
tableName: "example_categories",
fields: {
name: field.text({ required: true, minLength: 1, maxLength: 100 }),
},
admin: {
path: "example/categories",
list: {
columns: ["name", "createdAt"],
orderableFields: ["name"],
},
},
});Its sibling example.article turns on more blocks. Same engine, more fields, a busier list:

What you get
| From the definition | VitNode generates |
|---|---|
fields | A Postgres table with system columns and indexes, Zod schemas and a typed service |
admin | An AdminCP list with search, sorting and bulk actions, plus create and edit forms |
| Every content type | Staff routes and the can_view, can_create, can_edit and can_delete permissions |
publication | Draft and published states, a can_publish permission and Publish buttons |
publicApi | Read-only public routes that return only the fields you list |
delivery | Page URLs, SEO metadata, slug redirects and sitemap entries |
editorial | Revisions with restore, preview links and scheduling |
liveEditing | Field locks, an autosaved shared draft and presence in the AdminCP edit form |
localization | A translations table and per-language fields and publishing |
search | Records in the site search index |
Content types live in code and in your migrations, not in the database. There is no screen for creating a content type at runtime.
Pick a guide
| You want to | Guide |
|---|---|
| Build your first content type, with its AdminCP screen | First content type |
| Add drafts and a read-only public API | Public API |
| Understand how public reads are cached and refreshed | Caching |
| Give each record its own page with SEO metadata | Public pages |
| Control titles, descriptions, noindex and the sitemap | SEO |
| Make records findable in the site search | Search |
| Link records, group fields or repeat rows | Relations |
| Translate content into several languages | Translations |
| Store and render formatted text | Rich text |
| Keep revisions, share previews or schedule publishing | Editorial |
| Let several editors work on one record at the same time | Live editing |
| Change list columns, form sections or field components | AdminCP |
| Read and write content from your own API routes | Services |
| React to created, updated or published records | Events |
| Understand the generated tables and ship a schema change | Database |
| Check a content type before it goes live | Production |
Reference
- Options: every
defineContentTypeoption and how the options depend on each other. - Fields: every
field.*helper with its options, column type and form control. - Plugin files: the files and exports the app and the API read from your plugin.
- Live editing API: the HTTP API and deployment requirements behind live editing.