Core Concepts · Reference

Generated File Map

Exactly what grit generate resource writes, for every app in your project — the definitive index of paths, what each file is, and which are yours to edit versus regenerated. Filenames use the resource name (singular for Go, kebab-plural for routes/hooks).

One command, the whole stack

From a single field spec, Grit fans out a working, end-to-end feature. Here are the four files at the heart of it — switch tabs to see the same resource across Go and TypeScript:

grit generateGo backendSharedFrontendfans outresource Product--fields …models/product.goGORM structhandlers/product.goCRUD + importservices/product.gobusiness logicschemas/product.tsZodtypes/product.tsTS interfaceuse-products.tsReact Queryresources/products.tsadmin defproducts/page.tsxCRUD UI
One commandGo backendShared (Zod/TS)Frontend + admin
One command writes a working feature across every layer that exists in your project
type Product struct {
ID string `gorm:"primaryKey;size:36" json:"id"`
Name string `gorm:"size:255;not null" json:"name" binding:"required"`
Price float64 `gorm:"not null" json:"price"`
CategoryID string `gorm:"size:36;not null;index" json:"category_id"`
Category Category `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}
func (p *Product) BeforeCreate(tx *gorm.DB) error {
if p.ID == "" {
p.ID = uuid.New().String()
}
return nil
}

Excerpts, abbreviated for clarity — the real files are complete and runnable.

Backend + shared (always)

These are written for every architecture that has an API and a shared package.

PathWhat it is
apps/api/internal/models/<name>.goGORM model (UUID PK, BeforeCreate, relations)
apps/api/internal/services/<name>.goService layer — your custom business logic goes here
apps/api/internal/handlers/<name>.goGin CRUD handler (list/get/create/update/delete)
apps/api/internal/handlers/<name>_import.goCSV/Excel bulk-import handler
packages/shared/schemas/<name>.tsZod Create/Update schemas
packages/shared/types/<name>.tsTypeScript types (regenerated by grit sync)

Web app (if present)

PathWhat it is
apps/web/hooks/use-<plural>.tsReact Query hooks (Next.js) — src/hooks/ for the Vite kit

Admin panel (if present)

PathWhat it is
apps/admin/resources/<name>.tsResource definition (table + form + widgets) — src/resources/ on Vite
apps/admin/app/(dashboard)/resources/<plural>/page.tsxAdmin CRUD page — src/routes/_dashboard/resources/ on Vite

Mobile — Expo (if present)

PathWhat it is
apps/expo/hooks/use-<plural>.tsTyped React Query hook
apps/expo/app/<plural>/index.tsxList screen
apps/expo/app/<plural>/[id].tsxDetail screen
apps/expo/app/<plural>/new.tsxCreate screen
apps/expo/app/<plural>/edit/[id].tsxEdit screen
apps/expo/components/resource-forms/<plural>-form.tsxShared form component

Desktop — Wails (if present)

PathWhat it is
apps/desktop/frontend/src/hooks/use-<plural>.tsReact Query hook (calls Wails bindings)
apps/desktop/frontend/src/routes/_app/<plural>.index.tsxList route
apps/desktop/frontend/src/routes/_app/<plural>.new.tsxCreate route (+ detail / edit routes)

Files it edits (marker injection)

Rather than overwrite shared files, Grit injects at // grit:* markers. Keep the markers in place — they're how generation and seeding stay idempotent.

PathWhat it is
apps/api/internal/models/user.goModel registered in Models() at // grit:models
apps/api/internal/routes/routes.goRoutes registered at // grit:routes:*
packages/shared/schemas/index.tsSchema re-exported at // grit:schemas
apps/admin/resources/index.tsResource registered at // grit:resources
Yours vs regeneratedEverything above is your code once generated — edit models, add service methods, restyle screens freely. The one exception is packages/shared/types/*, which grit sync regenerates from your Go structs; put custom logic in the service layer (which regeneration never touches), not in the types.
Escape hatchNeed to pull a resource back out? grit generate remove resource <Name> deletes exactly these files and unwinds the marker injections — a clean inverse of generation.