Core Concepts · Reference
Field Types
The complete set of field types you can pass to grit generate resource --fields. Each one drives the Go struct field, the shared TypeScript type, the Zod schema, and the default admin form control and table column — from one declaration.
Field syntax
A field is name:type, with optional extra segments. Separate multiple fields with commas inside --fields.
Terminal
$grit generate resource Product --fields "name:string,price:float,category:belongs_to:Category,gallery:files:image"
- Modifiersname:string:unique — append :unique, :required, or :optional. String fields default to required; everything else defaults to optional.
- Slug sourceslug:slug:title — the 3rd segment is the field to slugify. Slugs are auto-unique and generated on save.
- belongs_tocategory:belongs_to (model inferred → Category) or author:belongs_to:User (explicit). Creates a <name>_id UUID foreign-key column.
- many_to_manytags:many_to_many:Tag — the related model is required. GORM builds the join table.
- File acceptsimage:file:image, doc:file:all, or att:file:[pdf,doc,image,video]. Aliases: image, video, audio, pdf, doc, all — or a bracketed list.
Type mapping
How each field type resolves across the stack. Source of truth: internal/generate/field.go.
DeclarationGoTypeScriptAdmin UI
Declare a field once — Grit resolves it into Go, TypeScript, Zod, and the admin UI| Type | Example | Go | TypeScript | Zod |
|---|---|---|---|---|
| string | name:string | string | string | z.string() |
| text | bio:text | string | string | z.string() |
| richtext | body:richtext | string | string | z.string() |
| int | qty:int | int | number | z.number().int() |
| uint | stock:uint | uint | number | z.number().int().nonnegative() |
| float | price:float | float64 | number | z.number() |
| bool | active:bool | bool | boolean | z.boolean() |
| datetime | published_at:datetime | *time.Time | string | null | z.string().nullable() |
| date | due:date | *time.Time | string | null | z.string().nullable() |
| slug | slug:slug:title | string | string | z.string() |
| belongs_to | category:belongs_to | string (FK) | string | z.string().uuid() |
| many_to_many | tags:many_to_many:Tag | []string | string[] | z.array(z.string().uuid()) |
| string_array | sizes:string_array | datatypes.JSONSlice[string] | string[] | z.array(z.string()) |
| file | image:file:image | *files.FileRef | FileRef | null | FileRefSchema.nullable() |
| files | gallery:files:image | files.FileRefs | FileRef[] | z.array(FileRefSchema) |
Primary keys are always UUID string (never uint); a belongs_to FK column is a matching UUID string.
Default admin rendering
Each type also picks a default form control and DataTable column format in the generated admin resource. You can override either in the resource definition.
| Type | Form control | Table format |
|---|---|---|
| string | Text input | text |
| text | Textarea | text |
| richtext | Rich-text editor (Tiptap) | richtext |
| int / uint / float | Number input | text |
| bool | Switch | boolean |
| datetime / date | Date / time picker | relative |
| slug | Auto-filled (read-only) | text |
| belongs_to | Relationship select (searchable) | text (dotted key) |
| many_to_many | Multi-select | — |
| string_array | Tag / chips input | text |
| file | Dropzone (single) | file |
| files | Dropzone (multiple) | files |
Escape hatchThe generated types are a starting point. Edit the Go struct tags, tune the Zod rules in
packages/shared/schemas, or override the form/table rendering in the admin resource definition — then run grit sync to keep TypeScript in step with Go. Grit generates opinions, not a cage.