JB logo

Command Palette

Search for a command to run...

yOUTUBE
Blog
Next

Grit Framework — Beginner CheatSheet

From zero to a full-stack app in under 5 minutes.

Grit Framework — Beginner Cheatsheet

Go + React. Built with Grit. From zero to a full-stack app in under 5 minutes.


1. Prerequisites

Make sure you have the following installed before starting:

ToolCheck VersionInstall From
Node.js (v18+)node -vnodejs.org
Go (v1.21+)go versiongo.dev
Gitgit --versiongit-scm.com
Docker Desktopdocker --versiondocker.com
pnpmpnpm -vnpm install -g pnpm

Tip: Make sure Docker Desktop is running before you proceed.


2. Install Grit

Open Git Bash (or any terminal) and run:

go install github.com/MUKE-coder/grit/cmd/grit@latest

Verify the installation:

grit version

You should see the current Grit version printed (e.g., v0.14.0).


3. Create a New Project

Navigate to the directory where you want your project, then scaffold it:

cd ~/projects
grit new test-app

Enter the project and open it in VS Code:

cd test-app
code .

4. Check for Port Conflicts

Grit uses the following ports — make sure they're all free before starting:

PortService
3000Web App (Next.js)
3001Admin Panel
5432PostgreSQL
6379Redis
8080Go API + Studio + Docs
9000MinIO (File Storage)

How to check if a port is in use

Windows (Git Bash / CMD / PowerShell):

netstat -ano | findstr :3000

If something shows up, note the PID (last column) and kill it:

taskkill //PID 12345 //F

Mac / Linux:

lsof -i :3000

Kill it:

kill -9 <PID>

Quick check all Grit ports at once (Windows):

for port in 3000 3001 5432 6379 8080 9000; do echo "Port $port:"; netstat -ano | findstr :$port; done

5. Install Dependencies

Open the terminal in VS Code (Ctrl + `` ``) and run from the project root:

pnpm install

This installs all client dependencies (web app, admin panel, shared packages).


6. Run Migrations

Set up the database tables:

grit migrate

7. Start the App

You need two terminals — one for the client, one for the server.

Terminal 1 — Start the client (Next.js apps):

grit start client

Terminal 2 — Start the server (Go API):

grit start server

8. You're Live!

Open your browser and visit:

URLWhat It Is
localhost:3000Web App — Your main frontend. Create a user and explore.
localhost:3001Admin Panel — Manage data, users, and resources.
localhost:8080/api/healthAPI Health Check — Confirm the Go API is running.
localhost:8080/studioGORM Studio — Visual database browser.
localhost:8080/docsAPI Docs — Auto-generated API documentation.

First thing to do: Go to localhost:3000, register a new user, and log in.


9. All CLI Commands

Quick Reference Table

CommandDescription
grit new <n>Scaffold a new full-stack project
grit new <n> --apiScaffold Go API only (no frontend)
grit new <n> --expoFull stack + Expo mobile app
grit new <n> --mobileAPI + Expo mobile app only
grit new <n> --fullEverything including a docs site
grit new <n> --style <variant>Admin style: default, modern, minimal, glass
grit generate resource <n>Generate full-stack CRUD resource
grit g resource <n>Shorthand for generate resource
grit remove resource <n>Remove a generated resource and clean up
grit rm resource <n>Shorthand for remove resource
grit add role <ROLE>Add a new role across all project files
grit start clientStart frontend apps (Next.js via Turborepo)
grit start serverStart Go API server
grit migrateRun GORM AutoMigrate for all models
grit migrate --freshDrop all tables then re-migrate
grit seedPopulate database with initial/sample data
grit syncSync Go models → TypeScript types + Zod schemas
grit updateUpdate the Grit CLI itself to latest version
grit upgradeUpdate your project's scaffold templates to latest
grit versionPrint CLI version
grit completionGenerate shell autocompletion script
grit helpShow help for any command

grit new — Scaffold a Project

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 app
grit new my-app --expo
 
# API + mobile only
grit new my-app --mobile
 
# Everything including docs site
grit new my-framework --full
 
# With admin panel style variant
grit 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.


grit generate resource — The Most Powerful Command

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 fields
grit generate resource Post --fields "title:string,content:text,published:bool"
 
# Shorthand
grit 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 file
grit g resource Post --from post.yaml
 
# With role-based access restriction
grit g resource Post --fields "title:string,content:text" --roles ADMIN,EDITOR

Field Type Reference

TypeGo TypeForm ComponentExample
stringstringText inputtitle:string
textstringTextareacontent:text
intintNumber inputviews:int
uintuintNumber inputstock:uint
floatfloat64Number inputprice:float
boolboolToggle switchpublished:bool
datetime*time.TimeDatetime pickerstarts_at:datetime
date*time.TimeDate pickerdue_date:date
slugstringAuto-generatedslug:slug or slug:slug:title
belongs_touint (FK)Relationship selectcategory:belongs_to
many_to_many[]uintMulti-selecttags:many_to_many:Tag
richtextstringRich text editor (Tiptap)body:richtext
string_arrayJSONSlice[string]Multi-image uploadimages:string_array

YAML Definition File (for complex resources)

# post.yaml
name: Post
fields:
  - name: title
    type: string
    required: true
    unique: true
  - name: content
    type: text
  - name: excerpt
    type: string
  - name: published
    type: bool
    default: "false"
  - name: views
    type: int
  - name: published_at
    type: datetime
grit generate resource Post --from post.yaml

grit remove resource — Clean Up a Resource

Deletes all generated files and cleans up injection markers:

grit remove resource Post
# or shorthand
grit rm resource Post

Use the same PascalCase name you used when generating (e.g., Post, BlogCategory).


grit add role — Add a New User Role

Updates 7 locations across your project in one command (Go constants, Zod enum, TypeScript type, shared constants, admin badge/filter/form):

grit add role MODERATOR
 
# Multi-word roles use underscores
grit add role CONTENT_MANAGER

grit start — Start Dev Servers

# Start all frontend apps (web + admin via Turborepo)
grit start client
 
# Start the Go API server
grit start server

Both commands auto-detect the project root, so you can run them from any subdirectory.


grit migrate — Database Migrations

# Run migrations (create/update tables)
grit migrate
 
# Fresh migration (drop everything and recreate)
grit migrate --fresh

grit seed — Seed the Database

Populate the database with initial or sample data:

grit seed

grit sync — Sync Go Types to Frontend

After manually editing a Go model, run this to regenerate TypeScript types and Zod schemas:

grit sync

When to use it:

  • After manually adding/removing fields from a Go model
  • After changing a field's type in a Go struct
  • After modifying GORM tags
  • After adding a new model file manually

You do NOT need grit sync after grit generate resource — the generator already handles it.


grit update vs grit upgrade

These are different commands — don't mix them up!

# Update the CLI TOOL itself to latest version
grit update
 
# Update your PROJECT'S scaffold files (admin, configs, web app) to latest templates
grit upgrade

10. Relationships

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.


belongs_to — Foreign Key (One-to-Many)

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"

What gets generated:

LayerWhat Happens
Go ModelCategoryID uint (FK column) + Category Category (association with foreignKey tag)
Handlerdb.Preload("Category") on all queries (eager loading)
Admin FormSearchable dropdown that fetches options from /api/categories
Admin TableDot notation column category.name showing the related name
Zod Schemacategory_id: z.number().int().min(1)

Generated Go Model:

type Product struct {
    ID         uint           `gorm:"primarykey" json:"id"`
    Name       string         `gorm:"size:255" json:"name" binding:"required"`
    CategoryID uint           `gorm:"index" json:"category_id" binding:"required"`
    Category   Category       `gorm:"foreignKey:CategoryID" json:"category"`
    Price      float64        `json:"price"`
    CreatedAt  time.Time      `json:"created_at"`
    UpdatedAt  time.Time      `json:"updated_at"`
}

many_to_many — Junction Table

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_many
grit g resource Product --fields "name:string,tags:many_to_many:Tag,price:float"

What gets generated:

LayerWhat Happens
Go ModelTags []Tag with gorm:"many2many:product_tags"
HandlerAssociation("Tags").Replace(tags) for create/update
Admin FormMulti-select with removable badge chips
Zod Schematag_ids: z.array(z.number().int())

Generated Go Model:

type Product struct {
    // ...other fields...
    Tags []Tag `gorm:"many2many:product_tags" json:"tags"`
}

has_one & has_many — Inverse Side (Manual)

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 it
type 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.


Full Example — E-Commerce with Both Relationship Types

# Step 1: Generate the parent models FIRST
grit g resource Category --fields "name:string,slug:slug,description:text"
grit g resource Tag --fields "name:string"
 
# Step 2: Generate Product with both relationship types
grit g resource Product --fields "name:string,category:belongs_to,tags:many_to_many:Tag,price:float,published:bool"
 
# Step 3: Run migrations
grit 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.


Customizing Relationships

Change the display field (defaults to name):

// 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 }

11. You're Ready to Build!

From here you can:

  • Generate resources with grit generate resource to create models, handlers, hooks, schemas, and admin pages in one command
  • Edit the frontend in apps/web/ (Next.js + Tailwind + shadcn/ui)
  • Edit the API in apps/api/ (Go + Gin + GORM)
  • Edit the admin panel in apps/admin/
  • Inspect your database at localhost:8080/studio

Common Gotchas

ProblemFix
grit: command not foundMake sure $GOPATH/bin is in your PATH. Run export PATH=$PATH:$(go env GOPATH)/bin
Docker containers won't startMake sure Docker Desktop is running. Try docker compose up -d manually in the project root
Port already in useSee Step 4 above to find and kill the process
pnpm: command not foundInstall it globally: npm install -g pnpm
Database connection refusedWait a few seconds after docker compose up — PostgreSQL needs time to initialize
Types out of sync after manual model editRun grit sync to regenerate TypeScript types and Zod schemas
Want to start freshRun grit migrate --fresh to drop all tables and re-migrate
CLI is outdatedRun grit update to install the latest CLI version
Project templates are outdatedRun grit upgrade to update scaffold files

Want More Details? Read the Full Docs

grit-vert.vercel.app

GitHub: github.com/MUKE-coder/grit > YouTube: @JBWEBDEVELOPER