Every full-stack app starts the same way: weeks of plumbing before a single feature ships. Grit asks a different question — what is the smallest set of commands that takes you from idea to a production-ready Go + React app?
If you are evaluating Grit, or just curious how we think about building a full-stack framework, this page explains the why behind the decisions — including the ones we know are not for everyone.
Grit brings coherence and speed to Go + React development without hiding the platform underneath it. Everything it generates is ordinary code in your repo, which means the framework can never become the thing standing between you and a fix.
It is MIT licensed, developed in the open, and supported by sponsors rather than a sales team. Releases are public, versioned, and shipped weekly.
For the longer story — why Go, why React, and what Grit borrows from Laravel and Rails — read the philosophy doc.
The boilerplate tax
Before you write the feature that matters, you re-solve the same problems you solved on the last project — and the one before that. None of it is hard. All of it is slow.
That is months of work that produces zero product differentiation. Grit treats all of it as solved — generated, wired, and hardened the moment you scaffold.
Compress the work
$grit new my-app --triple$grit generate resource Product \$ --fields "name:string,price:float,stock:int"
What Grit stands for
Every one of these costs something. A preference that costs nothing is not a principle, it is a feature list — so each one below names what you give up.
Grit writes real files into your repo — the model, service, handler, routes, hooks and admin page. Not a runtime dependency that does it invisibly at boot.
You give up a small repo. You get code you can read, edit, delete, and debug with a stack trace that points at your own file. There is no "fighting the framework" because there is no framework in the way — just Go and TypeScript you own.
Gin, GORM, Next.js, Postgres, Redis. Every one has years of production behind it and its answers already written down somewhere.
You give up novelty. We are not going to invent a router. The interesting part of your project should be your product, not the stack underneath it.
One way to do auth. One queue. One storage layer. Escape hatches where you need them, not a menu where you do not.
You give up the pleasure of choosing. You get a codebase where every Grit project looks the same, onboarding takes an afternoon, and an AI agent never has to guess which of six patterns you picked.
A resource is not a Go model or a TypeScript type. It is both — plus the handler, the Zod schema, the React Query hook and the admin page — generated together from one definition.
You give up picking your own frontend and backend languages. You get two halves that cannot drift apart, because one command writes both.
CSRF, strict CSP, rate limiting, SSRF defence, IDOR-safe ownership checks, field-level encryption, server-side sessions and a tamper-evident audit log — in the scaffold.
You give up the option to skip it. That is the point: security is the work that never wins a prioritisation meeting against a feature, so it ships before the meeting happens.
Every release runs a 73-check matrix across 13 project shapes — scaffold, install, build, typecheck, test — then gets re-verified by downloading the published binary and building a fresh project with it.
You give up a faster release cadence. Claims in a changelog are cheap; we would rather find the bug than describe the feature.
One command, full stack
grit generate resource emits the Go model, service, handler, routes, Zod schema, TypeScript types, React Query hooks, and an admin page — all consistent, all type-safe.
func (h *ProductHandler) List(c *gin.Context) {var products []models.Producth.DB.Where("user_id = ?", c.GetString("user_id")).Order("created_at desc").Find(&products)c.JSON(http.StatusOK, gin.H{"data": products})}
export function useProducts() {return useQuery({queryKey: ['products'],queryFn: async () => {const res = await api.get('/api/products')return res.data.data as Product[]},})}
What the trades buy you
Because there is one way to do each thing, an AI assistant has nothing to guess. Grit ships a SKILL.md, and grit mcp serve hands an agent the real route table and model definitions over MCP — parsed from your source, read-only.
The hardening in every scaffold is work no one budgets for: SSRF defence, IDOR-safe ownership checks, GDPR export and erasure, SSO with SAML, field-level encryption. Already there, already tested.
Embed a SPA in the Go binary, split web / admin / API into a monorepo, go API-only, or add mobile and desktop. The generators and conventions do not change — only the shape does.
Honest limits
A framework that fits everything fits nothing. Here is where Grit does not fit — better to find out on this page than three weeks into a rewrite.
Grit is Go on the backend, and that is not configurable. If you are TypeScript end to end, AdonisJS or Nest will make you happier, and we would rather you were happy than converted.
You can swap them — it is your code. But you would be working against the generators, and that cost compounds with every resource you add.
The batteries become weight you never use. `--api` trims a lot of it, but a plain Gin binary may genuinely be the simpler answer.
Grit is young. Fewer Stack Overflow answers, fewer third-party plugins, fewer people who have hit your exact bug. What you get instead is a maintainer who ships weekly and answers questions directly.
If none of those describe you, the rest of the decisions on this page were made with your project in mind.
Join the WhatsApp community for questions, tutorials, and guidance from people shipping Grit apps, and from the person who builds it. No question is too small.
Install the CLI and scaffold a production-ready Go + React app in minutes.
$curl -fsSL https://gritframework.dev/install.sh | sh
Grit v3.170.0 · MIT licensed · Go + React