Opinionated by design. Describe a resource and Grit writes the Go model, API, migrations, TypeScript types, React hooks and admin screen. Auth, RBAC, jobs, storage, realtime, observability and deploy: all configured out of the box.
$iwr -useb https://gritframework.dev/install.ps1 | iex
Detects an existing install and runs grit update, otherwise pulls the right binary for your OS. All install options
package handlers// Written for you, along with the model, migration,// service, routes, Zod schema, TS types, React Query// hooks and a working admin page.func (h *ProductHandler) List(c *gin.Context) {var products []models.Producth.DB.Where("user_id = ?", c.GetString("user_id")).Find(&products)c.JSON(http.StatusOK, gin.H{"data": products,})}
One Postgres, identical container limits, the same 10,000 rows, the same k6 script, every framework in production shape and on its own ORM. Each has a page showing exactly how to reproduce it, including the two rows against Bun that repeated measurement could not separate, and the three bugs this benchmark found in Grit itself.
One indexed lookup and a JSON encode: the cleanest read of framework overhead





Each framework was run head to head against Grit, back to back, three times, medians reported, zero failed requests. 50 concurrent users, 4 CPUs and 2 GB per container, one shared Postgres, the same 10,000 rows, every framework on its own ORM. Bar heights are scaled within each pair, because each pair is a separate run. Compare the two bars inside a group, not heights across groups. The printed figures are the real measurements.
MethodologyThe benchmark above measures a request. This measures a Monday: how many of the 26 things a real product needs are already running the first time you open the app. Grit has 22. The 4 it does not have are in the table too, because a comparison where one column wins every row is not a comparison.
| Capability | Laravel | Next.js | Encore.ts | Express | ||
|---|---|---|---|---|---|---|
| Identity | ||||||
| Email and password authRegister, sign in, refresh, forgot and reset password, with the screens. | Generated for you. Scaffolded handlers, JWT with rotating refresh tokens, and the pages | Official package, you wire it. Breeze or Fortify, installed separately | Built into the framework. django.contrib.auth, with views you template yourself | Third-party package. Auth.js, formerly NextAuth | Third-party package. Auth handlers are a hook you implement | Third-party package. Passport or a hand-rolled equivalent |
| Roles and permissionsRoles as database rows rather than an enum, per-resource permissions registered by the generator, and a UI to edit them without a deploy. | Generated for you. Every generated resource registers its own permissions | Third-party package. spatie/laravel-permission is the de facto choice | Built into the framework. Groups and permissions, surfaced in the admin | Third-party package | Third-party package | Third-party package |
| Two-factor with backup codesTOTP enrolment, a QR code, ten hashed single-use recovery codes. | Generated for you. In the generated admin, not a wiring exercise | Official package, you wire it. Fortify | Third-party package. django-otp | Third-party package | Not provided | Third-party package |
| Enterprise SSO (OIDC and SAML)Connections stored as rows, so onboarding a customer is a form and not a deploy. | Generated for you. OIDC and SAML 2.0, one connection per customer | Third-party package. Socialite covers OAuth; SAML is third party | Third-party package. python-social-auth or djangosaml2 | Third-party package. Auth.js covers OIDC; SAML is separate | Not provided | Third-party package |
| Server-side sessions with device revokeEvery refresh token backed by a row, replay detection, and a screen listing the devices signed in. | Generated for you. Rotation with replay detection, idle and absolute timeouts | Built into the framework. Sessions are core; per-device revoke is yours to build | Built into the framework. Sessions are core; per-device revoke is yours to build | Third-party package | Not provided | Third-party package |
| Security and compliance | ||||||
| Security dashboardBlocked requests, suspicious agents, rate-limit trips and lockouts, visible in the app rather than in a log aggregator you have to buy. | Generated for you. Sentinel, in the generated admin | Not provided | Not provided | Not provided | Not provided | Not provided |
| Tamper-evident audit logA hash-chained record of every mutation, with one button that replays the chain and names the first row that fails. | Generated for you. SHA-256 chain, plus OCSF export for a SIEM | Third-party package. owen-it/laravel-auditing and similar | Third-party package. django-auditlog and similar | Not provided | Not provided | Not provided |
| GDPR export and erasureA subject access export and a delete that actually cascades. | Generated for you. Endpoints and admin screens | Third-party package | Third-party package | Not provided | Not provided | Not provided |
| Hardened by defaultSecurity headers, CSRF, body-size limits, rate limiting and lockout wired before you write a line. | Generated for you. OWASP-aligned defaults in the scaffold | Built into the framework. CSRF and headers are core; rate limiting is core | Built into the framework. CSRF, XSS and clickjacking middleware are core | Third-party package. Headers are yours to configure | Built into the framework. Validation and CORS handled by the runtime | Third-party package. helmet, express-rate-limit, and so on |
| Operations | ||||||
| Background jobs with a queue UIA worker, retries, and a screen showing what failed and why. | Generated for you. asynq, with the dashboard scaffolded | Built into the framework. Queues are core; Horizon adds the UI as a first-party package | Third-party package. Celery, plus Flower for the UI | Not provided | Built into the framework. Pub/Sub and cron are part of the framework | Third-party package. BullMQ and similar |
| Request tracing and metrics in-appLatency, error rates and slow queries, without adding a vendor. | Generated for you. Pulse, in the generated admin | Official package, you wire it. Telescope | Third-party package. django-silk or debug-toolbar, development oriented | Not provided | Built into the framework. Tracing is a core part of the platform | Third-party package |
| File storage with image processingS3-compatible uploads, presigned URLs, and thumbnails generated for you. | Generated for you. S3, R2 or MinIO, with a dropzone in the admin | Built into the framework. Flysystem is core; image processing is a package | Built into the framework. Storage backends are core; processing is a package | Third-party package | Built into the framework. Object storage is a framework primitive | Third-party package. multer, and an SDK |
| Scheduled database backupA cron entry, an off-site target, and a restore path you can test. | Generated for you. Scheduled, with a screen | Third-party package. spatie/laravel-backup | Third-party package. django-dbbackup | Not provided | Not provided. Managed by the cloud provider | Not provided |
| Deploy commandOne command from a working tree to a running server with TLS. | Built into the framework. grit deploy: SSH, systemd, Caddy with automatic TLS | Third-party package. Forge and Envoyer are paid services | Not provided | Third-party package. Trivial on Vercel, yours anywhere else | Built into the framework. Deploys to Encore Cloud or your own AWS and GCP | Not provided |
| One-click managed hostingPush, and someone else runs it. Grit deploys to a server you own, which is cheaper and more portable, and is more work than a git push to a platform that knows your framework. | Third-party package. Any VPS or container host; no platform is tailored to it | Third-party package. Forge and Vapor are paid services | Third-party package | Built into the framework. Vercel is built by the same team and it shows | Built into the framework. Encore Cloud is part of the product | Third-party package |
| InternationalisationTranslation catalogues, locale negotiation and pluralisation. Grit formats numbers and dates by locale but ships no translation system, which is a real gap next to the two frameworks that have had one for twenty years. | Official package, you wire it. grit add i18n: next-intl plus translated API messages. The generated admin chrome is not translated yet, so this is a foundation rather than a finished feature | Built into the framework. Translation files, helpers and pluralisation are core | Built into the framework. gettext, locale middleware and translated admin | Third-party package. next-intl or similar | Not provided | Third-party package. i18next and similar |
| Developer experience | ||||||
| Full-stack resource generationOne command emitting the model, migration, service, handler, validation schema, TypeScript types, data-fetching hooks and an admin screen. | Generated for you. grit generate resource, every layer at once | Official package, you wire it. make:model -mcr covers the backend layers | Not provided. startapp gives you empty files | Not provided | Not provided | Not provided |
| Typed client from the backendBackend types crossing the language boundary without being retyped by hand. | Generated for you. Go structs to TypeScript types, Zod schemas and React Query hooks | Third-party package. Typescript transformers and similar | Third-party package. drf-spectacular plus a generator | Not provided. Same language, so the question does not arise | Built into the framework. Generates typed clients from your API definitions | Third-party package. Via an OpenAPI generator you wire up |
| Admin panelTables, filters, forms, bulk actions and detail views over your own models. | Generated for you. Generated per resource, in four themes | Third-party package. Filament is third party; Nova is first party and paid | Built into the framework. The Django admin, and it is still the benchmark | Not provided | Not provided | Not provided |
| Database browser in the appBrowse and edit rows without leaving the running application. | Built into the framework. GORM Studio, mounted at /studio | Third-party package. Tinker is a REPL rather than a browser | Built into the framework. The admin covers much of this | Not provided | Built into the framework. A local development dashboard | Not provided |
| API documentation from the codeAn OpenAPI document and a browsable reference, kept current by the generator. | Generated for you. Emitted as routes are generated, served in-app | Third-party package. Scribe or L5-Swagger | Third-party package. drf-spectacular | Not provided | Built into the framework. Generated from the API definitions | Third-party package. swagger-jsdoc and similar |
| GraphQL APIGrit is REST and OpenAPI only. If GraphQL is a requirement, the mature options are elsewhere and this is the wrong framework for the job. | Not provided. REST and OpenAPI only | Third-party package. Lighthouse | Third-party package. Strawberry or Graphene | Third-party package. Apollo or similar | Not provided | Third-party package. Apollo Server |
| Reach | ||||||
| Web frontendA public site or app, typed against the same API. | Generated for you. Next.js or Vite, your choice at scaffold time | Built into the framework. Blade, with Inertia or Livewire | Built into the framework. Templates | Built into the framework. This is what Next.js is | Not provided. Bring your own | Not provided. Bring your own |
| Server-rendered templatingA page rendered by the backend with no JavaScript build. Grit is an API with React clients by design, so for a content site with a little interactivity Blade or Django templates are simply less machinery. | Not provided. API plus React by design | Built into the framework. Blade, with Livewire for interactivity | Built into the framework. The template language is core | Built into the framework. Server components render on the server | Not provided | Third-party package. ejs, pug and similar |
| Mobile appA React Native client sharing the API types. | Generated for you. Expo, scaffolded with the shared types | Not provided | Not provided | Not provided | Not provided | Not provided |
| Desktop appA native window, offline-first with a local database and sync. | Generated for you. Wails, with an offline SQLite store and a sync engine | Third-party package. NativePHP is young and third party | Not provided | Third-party package. Electron or Tauri, wired by you | Not provided | Not provided |
| Running without installing anything | 22/26 | 7/26 | 10/26 | 3/26 | 9/26 | 0/26 |
Running without installing anything: 22/26 in Grit. The next closest is 10/26.
Every row here can be built in every framework listed. The table is not about what is possible, it is about how much is already running the first time you open the app. Django's admin and Laravel's queues and observability are first rate, and they are marked as such. Express is a router and Bun is a runtime, so Express scoring low is a statement about scope and not about quality, which is also why Bun is not a column here at all.
What ships in the boxEvery one of these ships in a generated project. Switch on what you need, leave the rest off.
A full-stack meta-framework that turns one CLI command into a working Go API, React frontend, and admin panel, with everything you usually wire up by hand already wired up.
Pick your architecture (single binary, monorepo, mobile, desktop) and one command scaffolds the entire repo: Go API, React frontend, admin panel, Docker, CI, all wired together.
Describe a resource (Product · Order · Invoice). Grit emits the Go model, service, handler, routes, Zod schema, React hooks, and admin page: typed end-to-end, no glue code.
grit deploy cross-compiles, uploads, sets up systemd, and configures Caddy with auto-TLS. Or push to git and let your platform of choice run the bundled Dockerfile.
What you get out of the box
Web, desktop, mobile and a documented API, from one Go backend and one set of generated types. Every screenshot below is a real generated project, next to the commands that produce it.

A screenshot of a generated project, not a mockup.
Two front-ends against one Go API: a public web app and a resource-driven admin panel with tables, filters, multi-step forms and RBAC already wired up.
grit new myapp --tripleGo API + web app + admin panelcd myapp && docker compose up -dPostgres, Redis, MinIO, Mailhogpnpm install && grit migrate && grit seeddeps, tables, a demo admin logingrit startall three, one terminalAdmin on :3001, web on :3000, API on :8080.
Not a scaffold you finish by hand. Uploads that know what they accept, foreign keys you can fill without leaving the page, line-item tables that total themselves, wizards that save a step at a time, and a desktop app that keeps taking input with the network off.

Declare a field as file or files and add what it accepts: image, pdf, zip, doc, video, or a bracketed list. You get a dropzone with the right filter, image previews, per-type icons, size caps and progress, on both create and edit.
grit generate resource Product --fields \ "name:string,category:belongs_to:Category,price:float,\ cover:file:image,gallery:files:image,\ spec_sheet:file:pdf,downloads:files:[zip,doc],\ description:richtext,published:bool"
One command: model, migration, API, types, hooks and this form.
Uploads go browser-to-storage through a presigned URL, and the field’s accept list is enforced on the server too: a field declared file:pdf will not take a PNG even if the client asks nicely.
Every scaffolded admin ships with four complete themes: not palettes, but coordinated typography, auth pages, dashboard and brand colour. Pick one at grit new, or change your mind later with one line in .env.

The default. Professional blue on white: teams, dashboards, internal tools.
grit new myapp --theme atlasTHEME=atlasOne line in .env. Themes are CSS variables, so switching one costs a restart, not a rewrite.
Real screenshots of a generated admin: same resources, same seeded data, same viewport. Only the theme changes.
Permissions, brute-force protection, golden-signal metrics, an audit timeline, scheduled backups, S3 uploads, a job queue and a cron scheduler: each with a real screen, not a config file and a README. This is what grit new gives you on day one.

Every resource you generate registers its own create / view / edit / delete permissions automatically. Roles are rows in your database, not constants in a file, so the people running the app can change them without a deploy.
Grant a whole resource and it keeps any action added to it later, so generating a new resource never silently widens or narrows an existing role.
Every one of these ships with grit new. There is nothing to install and nothing to wire up.
Sign-in pages, a JWT pair, revocable server-side sessions, Google and GitHub, TOTP with backup codes, database-backed roles, and enterprise SSO over OIDC or SAML. Working on the first run, not a tutorial to follow.

Login, register, forgot-password and reset-password, themed with the rest of the admin and wired to a Go API that already hashes with bcrypt and issues a JWT pair.
Not included, so you are not surprised later: there is no email-verification flow (the field exists and social sign-in sets it, but nothing sends a verification mail), and no API-key authentication; machine callers use the same JWT flow.
GDPR export and erasure with a tamper-evident journal, SSO per customer over OIDC or SAML, access-review campaigns for SOC 2, and a hash-chained audit trail that exports to your SIEM. Built in, not bought later.

Right-to-access exports and right-to-erasure, with every erasure written to a hash-chained journal that can prove it has not been edited since.
What Grit does not ship: a cookie-consent banner, a signed SBOM, or data-residency controls. Field-level encryption, a go-live checklist and dependency scanning in CI are included, but the paperwork side of a certification is still yours.
The generator writes a resource definition; after that it is ordinary TypeScript you own. Columns, filters, row and bulk actions, twenty field types, wizards, dropzone variants, changed by editing a file, not by fighting a generator that wants to overwrite it.
import { defineResource } from "@/lib/resource";export const productResource = defineResource({name: "Product",slug: "products",endpoint: "/api/products",icon: "Package",label: { singular: "Product", plural: "Products" },// sheet · modal · page · modal-steps · page-stepsformView: "sheet",// Sidebar placementgroup: "Catalog", // section heading to sit underadminOnly: false, // hide from non-adminshidden: false, // keep routable, drop from the sidebartable: { /* columns, filters, actions, export, import */ },form: { /* fields, layout, steps, groups */ },// Four auto stat cards, or your ownstats: true,dashboard: { enabled: true },});
grit generate resource writes this file for you. Everything past that point is ordinary TypeScript you own. There is no regeneration step that overwrites your edits.
Grit is opinionated about structure, not about who you rent from. Each of these is one environment variable, with a local default that works before you have any cloud account at all.
One DATABASE_URL. The driver is chosen by the shape of the DSN, so moving from a local file to a managed Postgres is an env change and nothing else. GORM is the ORM either way, so your models and migrations do not care.
DATABASE_URLsqlite:… or a postgres:// URLThe default, and what docker compose brings up locally.
DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=require
Any Postgres-compatible host works: it is a standard DSN, not a per-vendor integration.
A file, or :memory: for tests. Pure-Go driver, so no CGO.
DATABASE_URL=sqlite:./app.db DATABASE_URL=sqlite::memory:
Ideal for the first five minutes and for the generated Go test suite.
MySQL is not supported. The connector picks SQLite or Postgres by DSN prefix: there is no third dialector to fall back to.
// One URL. The driver is chosen by the DSN's shape.// DATABASE_URL=sqlite:./app.db// DATABASE_URL=sqlite::memory:// DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=require// Models are ordinary GORM structs — generated, then yours.type Product struct {ID string `gorm:"primaryKey" json:"id"`Name string `gorm:"not null" json:"name"`CategoryID string `json:"category_id"`Category *Category `json:"category,omitempty"`Price float64 `json:"price"`CreatedAt time.Time `json:"created_at"`}// grit migrate runs AutoMigrate across every registered model,// and reports what it created or altered rather than doing it silently:// + created *models.Product// ~ altered *models.Invoice (+2 columns)
Which means it runs anywhere: a $5 VPS, a managed platform, or your own Docker host. Pick a target for the actual steps, what it costs, and the thing that catches people out.
Good fit: A single Go binary you want in several regions without running servers. The best fit for Grit’s single-binary mode.
Launch without deploying
Let Fly detect the Dockerfile and write a fly.toml, but stop before it ships anything: the defaults need two changes first.
fly launch --no-deploy
Point the health check at the API
Fly checks `/` by default. Grit serves its health endpoint at `/api/health`, so without this the machine is marked unhealthy and cycled forever while the app is running perfectly.
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = "suspend"
auto_start_machines = true
min_machines_running = 1
[[http_service.checks]]
interval = "15s"
timeout = "3s"
grace_period = "10s"
method = "GET"
path = "/api/health"Attach Postgres and Redis
Attaching sets DATABASE_URL for you. Redis comes from Upstash through Fly and gives you REDIS_URL.
fly postgres create --name my-app-db fly postgres attach my-app-db fly redis create
Machines suspend on idle by default. The first request after a quiet period pays the wake-up cost: set `min_machines_running = 1` for anything user-facing.
Teams that want a click-through dashboard for everything: Fly is CLI-first and expects you to read a TOML file.
The generator emits the Go handler and the typed client: schemas, TypeScript types and React Query hooks. The same hook then works in a Next.js app, a TanStack SPA, an Expo phone app and an offline-capable desktop binary. Rename a field in the Go struct and every one of them stops compiling until you fix it.
package handlers// Written once by:// grit generate resource Productfunc (h *ProductHandler) List(c *gin.Context) {var products []models.Producth.DB.Where("user_id = ?", c.GetString("user_id")).Find(&products)c.JSON(http.StatusOK, gin.H{"data": products,})}
'use client'import { useProducts } from '@/hooks/use-products'export default function ProductsPage() {const { data: products, isLoading } = useProducts()if (isLoading) return <Skeleton />return (<ul>{products.map((p) => (// p is typed from the Go struct — rename the// field in Go and this stops compiling.<li key={p.id}>{p.name} — {p.price}</li>))}</ul>)}
Generated React Query hook, generated types. No fetch wrapper to write.
Grit is the chip on the board. Auth, jobs, storage, AI, observability, webhooks, realtime, and cache all light up the moment you scaffold, so you spend your time on product not plumbing.
JWT · OAuth · 2FA
100+ models · stream
S3 · R2 · MinIO
asynq · retries
Stripe · HMAC · replay
WebSockets · channels
middleware · TTL
Resend · templates
From git push to a running app with auth, storage, jobs, realtime, and AI all on the same wire: no glue code, no dashboard tabs to hunt through.

Grit has opinions on everything: routing, queues, auth, storage, AI. That is thousands of decisions an AI agent does not have to make, and the code it writes lands in the same shape a person would have written.
func (h *AuthHandler) Login(c *gin.Context) {var req loginRequestc.ShouldBindJSON(&req)var user models.Userh.DB.Where("email = ?", req.Email).First(&user)if !user.CheckPassword(req.Password) {c.JSON(401, gin.H{"error": "Invalid credentials",})return}tokens, _ := h.AuthService.GenerateTokenPair(user.ID, user.Email, user.Role)c.JSON(200, gin.H{"data": gin.H{"user": user, "tokens": tokens},})}
Pulse gives full observability: find errors and performance issues before your team does. Mounted at /pulse/ui on every Grit project.
Grit scaffolds Next.js and TanStack Router front-ends, and generates the typed client for both. The API itself is plain REST with an OpenAPI document, so anything that speaks HTTP can call it, but these are the ones we generate and test.
Explore front-endsFlexible Architecture
Coming from Laravel? Choose Single. MERN stack? Choose Double. Building a SaaS? Choose Triple.
Go + embedded SPA
--singleWeb + API monorepo
--doubleWeb + Admin + API
--tripleGo backend only
--apiAPI + Expo
--mobileOne-Command Deploy
grit deploy builds your app, uploads via SSH, configures systemd, and sets up Caddy with auto-TLS.
$ grit deploy --host deploy@server.com --domain myapp.com→ Building frontend...→ Building Go binary (linux/amd64)...→ Uploading binary to /opt/myapp/→ Setting up systemd service...→ Configuring Caddy reverse proxy...✓ Deployment successful!Live at: https://myapp.com
Framework Comparison
| Feature | Grit | Next.js | Laravel |
|---|---|---|---|
| Go Backend | |||
| React Frontend | |||
| Admin Panel | |||
| Code Generator | |||
| JWT + OAuth2 | |||
| Two-Factor Auth | |||
| File Storage | |||
| Background Jobs | |||
| AI Integration | |||
| One-Command Deploy | |||
| Multiple Architectures | |||
| Desktop App | |||
| Offline-First Sync | |||
| Audit Log + Hash Chain | |||
| Feature Flags | |||
| OWASP 2025 Hardened |
There are no testimonials here yet, and there will not be any invented ones. If Grit is running something of yours in production, tell us about it (the good and the parts that hurt) and it goes on this page with your name and a link back to you.
Built With Grit
Projects and products built with the Grit framework.
Self-hostable creator platform. Website builder, email marketing, courses, community.
Competitive Go coding platform with real-time WebSocket battles, ELO ranking, and sandbox execution.
Visual database browser for GORM. View tables, run queries, export data. Embedded in every Grit project.
Self-hosted observability SDK. Request tracing, DB monitoring, runtime metrics, Prometheus export.
WAF + rate limiting + brute-force protection with real-time threat dashboard.
Zero-annotation API documentation generator for Gin. Auto-generates OpenAPI spec with Scalar UI.
“I built Grit because I was tired of spending weeks setting up the same boilerplate for every project. Auth, admin panels, file uploads, background jobs. They should just work. Now they do. One command, and you have a production-ready app. That's the framework I wanted to use.”
Sponsors
Grit is free and MIT licensed. Sponsors fund the features, docs and releases, and get their name in front of everyone who builds with it.
Grit has no sponsors yet. Be the first, your logo goes at the top of this page, on the home page, in the README, and inside the CLI.
Become the founding sponsorFAQ
Basic Go knowledge helps, but Grit generates most of the code for you. The generated code follows clear patterns (handler → service → model) that are easy to extend. If you know any backend language, you'll pick it up fast.
Grit is designed for greenfield projects. It scaffolds the full project structure. However, you can use grit generate resource in existing Grit projects to add new features incrementally.
Yes. Every scaffolded project includes JWT auth, RBAC, rate limiting (Sentinel), observability (Pulse), error handling, CORS, gzip compression, connection pooling, and graceful shutdown. It's designed for production from day one.
Single embeds the React SPA into the Go binary via go:embed, leaving one file to deploy. Triple is a Turborepo monorepo with separate web app, admin panel, and API, and is the better fit for teams and complex products.
The backend (Go API) is identical regardless of frontend choice. You'd need to rebuild the frontend pages, but all hooks, types, and API patterns are the same. The admin panel components are also framework-agnostic React.
grit deploy is for self-hosted deployments. It SSHs to your server, uploads the binary, configures systemd, and sets up Caddy with auto-TLS. For Vercel/Railway, just push to git and the Dockerfile is included.
Yes, Grit is fully open source under the MIT license. The CLI, all plugins, and the documentation are on GitHub.
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 your first project. Or dive into the docs to plan your architecture first.
go install github.com/MUKE-coder/grit/v3/cmd/grit@latestgrit new my-app