Creates the full monorepo: Go API, Next.js web app, admin panel, shared types, Docker setup.
# Full-stack monorepo (default)grit new my-crm# Go API only (no frontend)grit new billing-service --api# Full stack + Expo mobile appgrit new my-app --expo# API + mobile onlygrit new my-app --mobile# Everything including docs sitegrit new my-framework --full# With admin panel style variantgrit new my-app --style modern
Project name rules: lowercase letters, numbers, and hyphens only. Must start with a letter. Min 2 chars, max 64 chars.
Generates 8 new files and modifies up to 10 existing files in one command: Go model, handler, service, Zod schema, TypeScript types, React Query hooks, admin page, and resource definition — all wired together.
# Basic resource with inline fieldsgrit generate resource Post --fields "title:string,content:text,published:bool"# Shorthandgrit g resource Post --fields "title:string,content:text,published:bool"# Interactive mode (prompts you field by field)grit g resource Invoice -i# From a YAML definition filegrit g resource Post --from post.yaml# With role-based access restrictiongrit g resource Post --fields "title:string,content:text" --roles ADMIN,EDITOR
# Update the CLI TOOL itself to latest versiongrit update# Update your PROJECT'S scaffold files (admin, configs, web app) to latest templatesgrit upgrade
Grit handles relationships automatically when you use belongs_to and many_to_many field types. Everything is generated for you: Go model associations, handler Preloads, Zod schemas, TypeScript types, and admin form components.
Use when a resource belongs to a parent (e.g., a Product belongs to a Category).
# Infer related model from field name (category → Category)grit g resource Product --fields "name:string,category:belongs_to,price:float"# Explicit related model (when field name ≠ model name)grit g resource Post --fields "title:string,author:belongs_to:User,content:text"
Use when a resource has many related records and vice versa (e.g., Products have many Tags, Tags have many Products). GORM auto-creates the junction table.
# Related model name is ALWAYS required for many_to_manygrit g resource Product --fields "name:string,tags:many_to_many:Tag,price:float"
What gets generated:
Layer
What Happens
Go Model
Tags []Tag with gorm:"many2many:product_tags"
Handler
Association("Tags").Replace(tags) for create/update
These are the inverse of belongs_to. Add them manually to the parent model when you need to query children from the parent side:
// Add to your Category model when you need ittype Category struct { // ...existing fields... Products []Product `gorm:"foreignKey:CategoryID" json:"products,omitempty"`}
The generator doesn't add inverse relationships automatically since not every parent needs to query its children.
# Step 1: Generate the parent models FIRSTgrit g resource Category --fields "name:string,slug:slug,description:text"grit g resource Tag --fields "name:string"# Step 2: Generate Product with both relationship typesgrit g resource Product --fields "name:string,category:belongs_to,tags:many_to_many:Tag,price:float,published:bool"# Step 3: Run migrationsgrit migrate
This gives you:
Product belongs to Category → searchable dropdown in admin form
Product has many Tags → multi-select with badge chips in admin form
Both relationships are eager-loaded in API responses
Admin table shows category.name via dot notation
Important: Always generate parent models (Category, Tag) before child models (Product) that reference them.
// Show user email instead of name in the dropdown{ key: "author_id", type: "relationship-select", relatedEndpoint: "/api/users", displayField: "email", // ← change this}
Change the API endpoint:
// Hit a filtered endpoint — only show active users{ key: "assignee_id", type: "relationship-select", relatedEndpoint: "/api/users?active=true", displayField: "name",}
Change what shows in the admin table:
// Show category slug instead of name{ key: "category.slug", label: "Category Slug", sortable: false }// Show author email{ key: "author.email", label: "Author Email", sortable: false }