What are the Batteries?

The included-out-of-the-box services and what they save you.

5 mineasy

Grit ships with five "batteries" — pre-wired services that solve real production problems. Cache, file storage, email, background jobs, AI. You don't have to choose, install, or configure them from scratch — they're there, ready, in the right shape. This chapter walks through each one in turn.

What is a "battery"?

A battery is an included service that:

  • Is enabled in docker-compose.yml for local dev.
  • Has a Go client / service initialized in main.go.
  • Is exposed to your code via a clean interface (e.g., s.cache.Get(key), s.mail.Send(to, ...)).
  • Has an admin page in the dashboard so non-devs can poke at it (Jobs dashboard, Mail preview, etc.).

The five batteries

Where the batteries plug in

Your handler │ ā–¼ Your service ──┬────► CACHE (Redis) — speed up reads, throttle │ ā”œā”€ā”€ā”€ā”€ā–ŗ STORAGE (S3 / R2 / MinIO) — file uploads │ ā”œā”€ā”€ā”€ā”€ā–ŗ MAIL (Resend) — transactional + marketing email │ ā”œā”€ā”€ā”€ā”€ā–ŗ JOBS (asynq + Redis) — background work, retries, cron │ └────► AI (Claude / OpenAI) — chat, embeddings, generation
Each battery has a dedicated service in the API. Handlers don't talk to Redis or Resend directly — they go through the service interface.

Why batteries-included matters

Without batteries, the "day-1" experience of a new API looks like this:

  1. Pick a Redis client library (3 choices, vibes-based decision).
  2. Wire connection pool, retry, env config.
  3. Decide on cache key naming convention.
  4. Wrap GET/SET in a service so you can test it.
  5. … and you haven't written any product code yet.

Multiply that by five (S3, mail, jobs, AI). Grit makes the decisions for you — opinionated, but the opinions are defensible. You can replace any battery later, but you don't have to choose to get started.

Where the batteries live in the code

apps/api/internal/
ā”œā”€ā”€ cache/         ← Redis cache service + middleware
ā”œā”€ā”€ storage/       ← S3/MinIO/R2 client + upload handler
ā”œā”€ā”€ mail/          ← Resend client + 4 HTML templates
ā”œā”€ā”€ jobs/          ← asynq client + worker definitions
└── ai/            ← Claude + OpenAI clients

Same shape: one package per battery, exposing a thin Go interface. Tests can swap in a fake; production wires the real thing.

Enabling / disabling at scaffold time

When you run grit new, the CLI asks which batteries you want. You can include everything (default for triple kit) or skip some for a minimal API. You can also add a battery later by running grit add battery <name>.

The admin dashboard for each battery

Every battery gets a page in the admin panel under /admin/system:

  • Jobs — live queue depth, running jobs, retry attempts, failed jobs you can re-queue.
  • Mail Preview — render templates with sample data without sending.
  • Files — browse + delete uploads.
  • Cron — see scheduled jobs, last/next run.
  • AI — usage stats, token spend.
Pay-as-you-grow. Local dev uses MinIO (S3 clone), a local Redis, and Mailhog (no real emails sent). Production swaps in real providers via env vars. Same code, different config. We'll show this for each battery in the next five lessons.

What this chapter covers, in order

  1. Redis cache — speed up reads, throttle, store ephemeral state.
  2. S3 storage — uploads, signed URLs, image processing.
  3. Mail (Resend) — transactional + marketing email with editable templates.
  4. Jobs (asynq) — background work, retries, cron.
  5. AI (Claude + OpenAI) — chat, embeddings, provider swap.

Each lesson follows the same template: what it does, how it's implemented, where the file lives, how to modify it, and a small exercise.

Quick check

A teammate asks "why not just install Redis ourselves and write the client?". What's the best one-line response?

What's next

Next lesson — Redis cache. Speed up reads, cache list endpoints, throttle expensive calls. The most common production performance win.

Spot a typo? Have an idea?

Help us improve this lesson. One click opens a GitHub issue with the lesson URL pre-filled — suggest clearer wording, report a bug, or request more depth. The course keeps improving thanks to learners like you.

Suggest an improvement on GitHub