Batteries Included: Every Feature That Ships with Grit
Every Grit project ships with 18 production-ready features pre-configured and wired together. This course walks through every single one — what it is, why it matters, how it's configured, and how to use it. By the end, you'll know your project inside and out.
What "Batteries Included" Means
Most frameworks give you a foundation and tell you to install plugins for everything else. Need caching? Find a Redis library, wire it up, write middleware. Need email? Pick a service, install an SDK, build templates. Need file uploads? Choose between S3, Cloudflare, or local storage, configure presigned URLs, handle multipart forms. Every feature is a research project.
Grit ships 18 features pre-configured and wired together in every project. They work on day one — no setup required. And because they're modular, you can remove any feature you don't need without breaking the others.
Here's the full list of what ships with every Grit project:
| # | Battery | What It Does |
|---|---|---|
| 1 | Redis Caching | GET response caching with TTL |
| 2 | File Storage | S3-compatible uploads (MinIO/R2/S3) |
| 3 | Email Service | Transactional email with 4 HTML templates |
| 4 | Background Jobs | Redis-backed async task queue |
| 5 | Cron Scheduler | Recurring tasks with cron expressions |
| 6 | AI Integration | Vercel AI Gateway (hundreds of models) |
| 7 | Two-Factor Auth | TOTP + backup codes + trusted devices |
| 8 | GORM Studio | Visual database browser at /studio |
| 9 | API Docs | Auto-generated OpenAPI 3.1 at /docs |
| 10 | Sentinel | WAF, rate limiting, security dashboard |
| 11 | Pulse | Request tracing, DB monitoring, metrics |
| 12 | Grit UI | 100 shadcn-compatible components |
| 13 | Docker Setup | Dev + production compose files |
| 14 | JWT Auth | Access + refresh tokens, middleware |
| 15 | CORS Middleware | Pre-configured cross-origin requests |
| 16 | Gzip Compression | Automatic response compression |
| 17 | Request Logging | Structured request/response logs |
| 18 | Connection Pooling | Optimized DB connection management |
Challenge: Count the Setup Time
Look at the table above. Pick any 5 features and estimate how long it would take you to set up each one from scratch in a new Go project (finding the library, reading docs, writing code, testing). Add up the total hours. That's the "Setup Tax" Grit eliminates.
Redis Caching
Caching is one of the most impactful performance optimizations you can make. Instead of querying the database every time a user requests the same data, you store the result in memory and serve it instantly. Grit's cache service wraps Redis with a clean Go API.
Grit's cache service exposes three methods — Set, Get, and Delete:
// Store a value with a 5-minute TTL
cache.Set("user:1", userData, 5*time.Minute)
// Retrieve it — returns the cached value or an error if expired/missing
cached, err := cache.Get("user:1")
// Explicitly remove a cached value (e.g., after an update)
cache.Delete("user:1")On top of the service, Grit includes cache middleware that automatically caches GET responses. When a GET request comes in, the middleware checks Redis first. If the response is cached, it returns it instantly without hitting your handler. If not, it calls your handler, caches the response, and returns it.
# Redis configuration
REDIS_URL=redis://localhost:6379Challenge: Explore the Cache Service
Open the file internal/service/cache_service.go in your Grit project. What methods does it expose? What parameters does Set accept? What does Get return when the key doesn't exist?
File Storage (S3-Compatible)
Every real application needs file uploads — profile pictures, documents, images, attachments. Grit's file storage service works with any S3-compatible provider: MinIO for local development, AWS S3 for production, or Cloudflare R2 for edge storage.
The upload flow in Grit works like this:
1. Client requests a presigned URL from your API
POST /api/uploads/presign { filename: "photo.jpg" }
2. API generates a presigned URL (valid for 15 minutes)
Response: { url: "https://storage.../photo.jpg?signature=...", key: "uploads/abc123.jpg" }
3. Client uploads the file directly to storage using the presigned URL
PUT https://storage.../photo.jpg?signature=... (file data)
4. Client confirms the upload to your API
POST /api/uploads/confirm { key: "uploads/abc123.jpg" }
5. API stores the file reference in the databaseConfiguration uses environment variables:
# File storage (S3-compatible)
STORAGE_ENDPOINT=localhost:9000
STORAGE_ACCESS_KEY=minioadmin
STORAGE_SECRET_KEY=minioadmin
STORAGE_BUCKET=uploads
STORAGE_USE_SSL=false
STORAGE_REGION=us-east-1localhost:9001 using the MinIO Console. The default credentials are minioadmin / minioadmin.Challenge: Upload a File
Start your Grit project with Docker Compose. Open the admin panel and upload a file (any image will do). Then open the MinIO Console at localhost:9001. Can you find the file in the uploads bucket? What is the full path of the file?
Email Service (Resend)
Transactional email is essential for any application — welcome emails, password resets, verification codes, notifications. Grit includes a complete email service powered by Resend with 4 pre-built HTML templates.
Grit ships 4 HTML email templates:
- • Welcome — sent when a user registers
- • Password Reset — sent when a user requests a password reset
- • Email Verification — sent to verify a user's email address
- • Notification — a generic template for system notifications
In development, emails are captured by Mailhog instead of being sent to real inboxes. This means you can test every email flow without configuring a real email provider.
// Send a welcome email to a new user
emailService.SendWelcome(user.Email, user.Name)
// Send a password reset link
emailService.SendPasswordReset(user.Email, resetToken)
// Send an email verification code
emailService.SendVerification(user.Email, verificationCode)
// Send a generic notification
emailService.SendNotification(user.Email, "Order Shipped", "Your order #1234 has shipped.")# Email (Resend)
RESEND_API_KEY=re_xxxxxxxxxxxx
EMAIL_FROM=noreply@myapp.com
# Local testing (Mailhog captures all emails)
SMTP_HOST=localhost
SMTP_PORT=1025localhost:8025 in your browser to see every email your application sends during development.Challenge: Catch a Welcome Email
Start your Grit project. Open Mailhog at localhost:8025. Now register a new user through the web app or API. Go back to Mailhog — do you see the welcome email? Open it and look at the HTML template. What information does it include?
Background Jobs (asynq)
Some tasks are too slow or too resource-intensive to run inside an HTTP request. Sending an email takes 200-500ms. Processing an image takes 1-2 seconds. Generating a report takes 5-10 seconds. You don't want users waiting for these. Background jobs let you offload work to a separate process that runs asynchronously.
Grit uses asynq, a Redis-backed job queue for Go. It ships with 3 built-in workers:
- • Email Worker — sends transactional emails asynchronously
- • Image Worker — processes uploaded images (resize, thumbnails)
- • Cleanup Worker — removes expired tokens, old sessions, temp files
Dispatching a job is a single function call:
// Enqueue an email job — returns immediately
err := jobs.Dispatch("email:welcome", map[string]interface{}{
"email": user.Email,
"name": user.Name,
})
// Enqueue an image processing job
err := jobs.Dispatch("image:resize", map[string]interface{}{
"file_key": "uploads/abc123.jpg",
"width": 800,
"height": 600,
})
// Enqueue with options: delay, retry, deadline
err := jobs.DispatchWithOptions("cleanup:tokens", nil, asynq.ProcessIn(1*time.Hour))The admin panel includes a Jobs dashboard where you can monitor queued, active, completed, and failed jobs in real time.
Challenge: Inspect the Jobs Dashboard
Open the admin panel and navigate to the Jobs page. Are there any queued or completed jobs? Try registering a new user — the welcome email is sent as a background job. Go back to the Jobs page. Do you see the email job in the completed list?
Cron Scheduler
Background jobs handle one-off tasks. Cron jobs handle recurring tasks — things that need to happen on a schedule. Clean up expired tokens every hour. Send a weekly digest every Monday. Generate reports every night at midnight.
0 9 * * 1 means "at 9:00 AM every Monday." The asterisk (*) means "every" — so * * * * * means every minute.Grit's cron scheduler uses the same worker pool as background jobs, so you don't need a separate process. Here's the cron expression format:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * *Common examples:
| Expression | Schedule |
|---|---|
| * * * * * | Every minute |
| 0 * * * * | Every hour (at minute 0) |
| 0 0 * * * | Every day at midnight |
| 0 9 * * 1 | Every Monday at 9:00 AM |
| 0 0 1 * * | First day of every month at midnight |
| 30 2 * * 0 | Every Sunday at 2:30 AM |
Challenge: Write Cron Expressions
Write the cron expression for each schedule:
- Every hour on the hour
- Every day at midnight
- Every Monday at 9:00 AM
- Every 15 minutes
- The first of every month at 3:00 AM
Check your answers against the table above. The last two are not in the table — you'll need to figure them out yourself.
AI Integration (Vercel AI Gateway)
Every Grit project ships with AI integration powered by Vercel AI Gateway. One API key gives you access to hundreds of models from dozens of providers — Claude, GPT, Gemini, Llama, Mistral, and more. No provider-specific code required.
Grit exposes 3 AI endpoints:
- • POST /api/ai/complete — single prompt in, single response out
- • POST /api/ai/chat — multi-turn conversation with message history
- • POST /api/ai/stream — streaming response (tokens arrive in real-time)
# AI Gateway configuration
AI_GATEWAY_URL=https://gateway.ai.vercel.app/v1
AI_GATEWAY_API_KEY=your-api-key-here
AI_GATEWAY_MODEL=anthropic/claude-sonnet-4-6curl -X POST localhost:8080/api/ai/complete \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{"prompt": "Explain REST APIs in 3 sentences."}'Challenge: Test AI Integration
If you have an AI Gateway API key, add it to your .env file. Start the API, get a JWT token by logging in, then test the /api/ai/complete endpoint with a prompt of your choice. What model did the response come from? (Check the response headers or body for provider information.)
Two-Factor Authentication (TOTP)
Passwords alone are not enough. If someone steals a user's password (phishing, data breach, reuse), they can access the account. Two-Factor Authentication (2FA) adds a second layer — even with the password, an attacker needs the user's physical device.
Grit's 2FA system includes:
- • Authenticator app support — works with Google Authenticator, Authy, 1Password, Bitwarden
- • 10 backup codes — one-time-use codes in case the user loses their device
- • Trusted devices — skip 2FA on recognized devices for 30 days
- • Zero external dependencies — the TOTP algorithm runs in pure Go, no third-party services
1. User enables 2FA
POST /api/auth/2fa/enable
→ Returns: QR code (base64) + secret key + 10 backup codes
2. User scans QR code with authenticator app
3. User verifies with the 6-digit code from the app
POST /api/auth/2fa/verify { "code": "123456" }
→ 2FA is now active
4. On next login, after password is verified:
POST /api/auth/2fa/validate { "code": "789012" }
→ Returns JWT tokenChallenge: Enable 2FA
Enable 2FA on your account. Scan the QR code with an authenticator app (Google Authenticator is free). Verify with a code. Then log out and log back in — you'll be prompted for the 6-digit code. Finally, test one of your backup codes: log out, and instead of the app code, enter a backup code. Does it work? Can you use the same backup code twice?
GORM Studio
GORM Studio is a visual database browser built directly into your Grit project. It runs at /studio and lets you browse tables, view and edit records, run raw SQL queries, and export schemas — all from your browser.
What you can do in GORM Studio:
- • Browse tables — see all tables, columns, types, and relationships
- • View and edit data — click any row to view details, edit fields inline
- • Run SQL queries — execute raw SQL and see results in a table
- • Export schemas — download your database schema as SQL
# Start your API
cd apps/api && go run cmd/server/main.go
# Open GORM Studio in your browser
http://localhost:8080/studio/studio route is disabled for security. You don't want random users browsing your database.Challenge: Explore GORM Studio
Open GORM Studio at localhost:8080/studio. Find at least 3 tables and describe what each one stores. How many columns does the users table have? Try running a SQL query: SELECT COUNT(*) FROM users;
API Documentation (Auto-Generated)
Grit automatically generates an OpenAPI 3.1 specification for your API and serves an interactive documentation UI at /docs. Every endpoint, every request body, every response shape is documented — and it stays in sync with your code because it's generated from your route definitions.
No annotations or comments needed. Grit reads your Gin route definitions and GORM models to generate the spec automatically. When you add a new resource with grit generate, the docs update automatically.
# Start your API
cd apps/api && go run cmd/server/main.go
# Interactive docs
http://localhost:8080/docs
# Raw OpenAPI 3.1 JSON spec
http://localhost:8080/docs/openapi.jsonChallenge: Test an Endpoint
Open localhost:8080/docs. Find the login endpoint. Use the interactive UI to send a login request with the test credentials. Did you get a JWT token back? Now find the "list users" endpoint — does it require authentication? Try calling it without a token and see what error you get.
Security (Sentinel)
Sentinel is Grit's built-in security layer. It protects your API from common attacks without you writing a single line of security code. It includes a WAF (Web Application Firewall), rate limiting, brute-force protection, security headers, and a threat dashboard.
429 Too Many Requests response.What Sentinel protects against:
- • SQL Injection — malicious SQL in query parameters or request bodies
- • XSS (Cross-Site Scripting) — injecting JavaScript into your pages
- • Brute-force login — repeated login attempts are throttled and blocked
- • Path traversal — attempts to access files outside allowed directories
- • Missing security headers — auto-adds CSP, HSTS, X-Frame-Options, and more
The Sentinel dashboard at /sentinel/ui shows real-time threat data: blocked requests, top attacking IPs, attack types, and rate limit violations.
Challenge: Visit the Security Dashboard
Open localhost:8080/sentinel/ui in your browser. What information does the dashboard show? Make 50 rapid requests to any endpoint (use a loop in your terminal). Does the rate limiter kick in? Check the dashboard again for the rate limit data.
Observability (Pulse)
You can't fix what you can't see. Pulse is Grit's built-in observability layer. It tracks every request, monitors database performance, collects metrics, and runs health checks — all viewable from a dashboard at /pulse/ui.
What Pulse tracks:
- • Request tracing — every request is logged with timing, status code, and unique request ID
- • Database monitoring — query count, average duration, slowest queries
- • Metrics — requests per second, error rate, response time percentiles (p50, p95, p99)
- • Health checks — database connectivity, Redis connectivity, disk space, memory usage
# Pulse dashboard
http://localhost:8080/pulse/ui
# Health check endpoint (JSON)
http://localhost:8080/pulse/health
# Metrics endpoint
http://localhost:8080/pulse/metricsChallenge: Generate Some Metrics
Make at least 10 API requests — a mix of GET, POST, and invalid requests (wrong URLs, missing auth). Then open Pulse at localhost:8080/pulse/ui. What is the average response time? Which endpoint is the slowest? How many errors did you generate?
Grit UI Components
Every Grit project ships with access to 100 pre-built UI components in the shadcn/ui format. These aren't npm packages — they're source code files you install directly into your project, giving you full control to customize them.
The components are organized into 5 categories:
| Category | Count | Examples |
|---|---|---|
| Marketing | 21 | Hero sections, feature grids, pricing tables, testimonials |
| Auth | 10 | Login forms, register forms, forgot password, 2FA pages |
| SaaS | 30 | Dashboard layouts, billing cards, settings pages, onboarding |
| E-commerce | 20 | Product cards, cart, checkout, order history, wishlists |
| Layout | 20 | Navbars, sidebars, footers, app shells, mobile menus |
# Browse all components in your browser
http://localhost:3000/components
# The registry API serves component metadata
GET /api/r.json → lists all 100 components
GET /api/r/hero-split.json → metadata + source for a specific component
# Install a component (shadcn CLI compatible)
npx shadcn@latest add "http://localhost:8080/r/hero-split.json"Challenge: Browse the Registry
Open the component browser at localhost:3000/components (or call the API at localhost:8080/api/r.json). How many components are in the "saas" category? Pick one component and explain how you would install it into your project.
Docker Setup
Grit ships with two Docker Compose files: one for development and one for production. The development compose file starts all the infrastructure services your project needs with a single command.
docker compose up. Each service runs in its own isolated container.The development compose file includes:
- • PostgreSQL — the primary database (port 5432)
- • Redis — caching and job queue (port 6379)
- • MinIO — S3-compatible file storage (port 9000, console on 9001)
- • Mailhog — email capture for testing (SMTP on 1025, UI on 8025)
# Start all development services
docker compose up -d
# Check running services
docker compose ps
# View logs for a specific service
docker compose logs -f postgres
# Stop everything
docker compose down
# Stop and remove all data (fresh start)
docker compose down -vThe production compose file (docker-compose.prod.yml) is optimized for deployment — it builds your Go API into a minimal Docker image, uses environment variables for configuration, and includes health checks.
Challenge: List Running Services
Run docker compose up -d to start all services. Then run docker compose ps. List every running service, its port mapping, and its status. Visit each service's UI: PostgreSQL has no UI, but check MinIO at localhost:9001 and Mailhog at localhost:8025.
Summary
You've now toured every battery that ships with a Grit project. Here's the complete list:
- Redis Caching — sub-millisecond response caching with automatic invalidation
- File Storage — S3-compatible uploads with presigned URLs (MinIO, R2, S3)
- Email Service — 4 HTML templates with Resend (Mailhog for local testing)
- Background Jobs — Redis-backed async task queue with 3 built-in workers
- Cron Scheduler — recurring tasks with cron expressions, same worker pool
- AI Integration — Vercel AI Gateway with hundreds of models, 3 endpoints
- Two-Factor Auth — TOTP with authenticator apps, backup codes, trusted devices
- GORM Studio — visual database browser at /studio
- API Documentation — auto-generated OpenAPI 3.1 spec at /docs
- Sentinel — WAF, rate limiting, brute-force protection, security dashboard
- Pulse — request tracing, DB monitoring, metrics, health checks
- Grit UI — 100 shadcn-compatible components across 5 categories
- Docker Setup — dev compose (4 services) + production compose
- JWT Authentication — access + refresh tokens with middleware
- CORS Middleware — pre-configured cross-origin request handling
- Gzip Compression — automatic response compression
- Request Logging — structured logs with request IDs
- Connection Pooling — optimized database connection management
Challenge: Tour Every Tool
Visit each of these URLs in your running Grit project and confirm they work:
localhost:8080/studio— GORM Studiolocalhost:8080/docs— API Documentationlocalhost:8080/pulse/ui— Pulse Observabilitylocalhost:8080/sentinel/ui— Sentinel Securitylocalhost:8025— Mailhog (email capture)localhost:9001— MinIO Console (file storage)
Take a screenshot of each. You now know every tool in your Grit project. These aren't plugins you installed — they shipped with your project from the very first command.
Enjoying the course?
Help us grow — star us on GitHub, subscribe on YouTube, and follow on LinkedIn.