Content Engine

Field Reference

Complete guide to adding and configuring field types in Content Engine, including Postgres mappings, Zod validation, and AdminCP controls.

Content Engine provides field descriptors exported from @vitnode/core/content via the field helper. Each field generates a typed Drizzle column, Zod validation schemas, and an interactive AdminCP input automatically.

Supported Field Types

Field MethodPostgres ColumnZod SchemaAdminCP Form Control
field.text()varchar(length)z.string()Text Input
field.textarea()text()z.string()Textarea
field.number()integer() / numeric()z.number()Number Input
field.boolean()boolean()z.boolean()Switch Toggle
field.enum()varchar(length)z.enum([...])Select Dropdown
field.dateTime()timestamp()z.date()Date / Time Picker
field.slug()varchar(length)z.string()Slug Generator
field.user()integer() (FK core_users)z.number()User Combobox
field.user({ multiple: true })Junction tablez.array(z.number())Multi-user Combobox
field.file()integer() (FK core_files)z.number()Drag-and-drop File Upload
field.file({ multiple: true })Junction tablez.array(z.number())Multi-file Gallery Uploader

Field Configurations

Text and Strings

Configure string length, required state, and multi-language support:

plugins/blog/src/content/post.ts
import { defineContentType, field } from "@vitnode/core/content"

export const postContentType = defineContentType({
  id: "blog.post",
  tableName: "blog_posts",
  fields: {
    title: field.text({
      required: true,
      minLength: 3,
      maxLength: 200,
      searchable: true,
      translatable: true,
    }),
    summary: field.textarea({
      maxLength: 500,
      translatable: true,
    }),
  },
})

Numbers, Booleans, and Enums

plugins/blog/src/content/post.ts
fields: {
  views: field.number({
    defaultValue: 0,
    min: 0,
    sortable: true,
  }),
  featured: field.boolean({
    defaultValue: false,
  }),
  status: field.enum({
    values: ["draft", "published", "archived"] as const,
    defaultValue: "draft",
  }),
}

Slugs, Dates, and User Relations

Auto-generate SEO slugs from other fields, pick dates, or link authors:

plugins/blog/src/content/post.ts
fields: {
  slug: field.slug({
    from: "title", // Automatically generated from title
    required: true,
  }),
  publishedAt: field.dateTime({
    defaultValue: () => new Date(),
  }),
  author: field.user({
    required: true,
  }),
  contributors: field.user({
    multiple: true,
  }),
}

Single and Multi-File Uploads

VitNode connects file fields directly to core_files with storage adapters (Local disk, S3, Cloudflare R2):

plugins/blog/src/content/post.ts
fields: {
  // Single cover image (max 5 MB)
  coverImage: field.file({
    required: false,
    maxBytes: 5 * 1024 * 1024,
    allowedExtensions: ["jpg", "png", "webp"],
    allowedMimeTypes: ["image/jpeg", "image/png", "image/webp"],
  }),

  // Gallery of screenshots
  gallery: field.file({
    multiple: true,
    maxFiles: 10,
    maxBytes: 10 * 1024 * 1024,
    allowedExtensions: ["jpg", "png", "webp"],
  }),
}

Automatic Multipart Upload Pipeline

In the AdminCP, AutoFormFile uploads attachments via TanStack Query and standard multipart API routes (POST /api/.../uploads/{field}). Uploaded records are stored in core_files and assigned by ID.


Common Field Options

Every field descriptor accepts these standard attributes:

Prop

Type

Learn More