Getting Started

Directory Structure

How a HAMR project is laid out.

Every HAMR project follows the same conventional layout. The structure is opinionated but unsurprising — anyone who's worked on a Go web app will feel at home.

project layout
myapp/
├── cmd/
│   ├── site/                  # main HTTP application
│   │   ├── main.go
│   │   └── Dockerfile
│   └── migrate/               # standalone migration runner
│       └── main.go
│
├── internal/
│   ├── api/                   # JSON API routes & handlers
│   │   └── server.go
│   ├── db/                    # connection + embedded migrations
│   │   ├── db.go
│   │   ├── models.go
│   │   └── migrations/
│   │       ├── 0001_init.up.sql
│   │       └── 0001_init.down.sql
│   ├── repo/                  # data access layer
│   │   ├── repo.go            # Store interface
│   │   └── postgres/          # Postgres implementation
│   ├── service/               # business logic
│   │   └── auth.go
│   ├── middleware/            # project-specific middleware
│   └── web/
│       ├── server.go          # route registration
│       ├── components/        # shared Templ components & layout
│       └── handler/           # one package per domain
│           ├── home/
│           │   ├── handler.go
│           │   └── home.templ
│           └── auth/
│               ├── handler.go
│               ├── login.templ
│               └── register.templ
│
├── static/                    # CSS, JS (vendored HTMX/Alpine), images
├── css/                       # Tailwind input (if using Tailwind)
├── docker/                    # docker-compose.yaml
├── docs/                      # ADRs, design docs
├── e2e-go/                    # browser-based E2E tests
├── scripts/                   # dev/ops scripts
│
├── go.mod
├── hamr.toml                  # dev server manifest
├── Makefile
├── CLAUDE.md                  # AI assistant guide
├── AGENTS.md                  # project conventions
├── .env.example
└── .env

Layered design

HAMR projects use a clean layering: handlers → services → repos → database. Each layer only depends on the one beneath it.

One package per domain

Each handler gets its own package. This keeps related code colocated, prevents circular imports, and makes it easy to find templates next to the handlers that use them.

internal/web/handler/books/
books/
├── handler.go         # request methods
├── list.templ         # GET /books
├── show.templ         # GET /books/:id
├── form.templ         # GET /books/new, GET /books/:id/edit
└── form_rules.go      # validation rules
Templates next to handlers
Templ files live next to the handlers that render them — not in a top-level templates/ directory. This makes refactoring much easier: when you delete a handler, its templates go with it.