Getting Started

Everything you need to build your first GOaT app.

The GOaT stack is Go (backend, templates, routing) + Alpine.js (reactive islands) + Tailwind CSS (styling). It also commonly includes HTMX for server-driven UI, DaisyUI for component classes, PostgreSQL + sqlc for data, and Redis for real-time SSE.

Why GOaT?

  • No bundler. Your JavaScript is two <script> tags.
  • No framework. Go’s stdlib handles routing, templates, and HTTP.
  • No hydration. The server returns HTML. The browser renders it.
  • One binary. go build → deploy. That’s it.

Prerequisites

  • Go 1.22+ (for enhanced ServeMux routing)
  • PostgreSQL (for data)
  • Redis (optional, for SSE/pub-sub)
  • Node.js (only for Tailwind CLI and Playwright tests)

Create a Project

mkdir myapp && cd myapp
go mod init github.com/you/myapp

Create the standard directory structure:

myapp/
├── cmd/
│   └── server/
│       └── main.go          # Entry point
├── internal/
│   ├── handler/              # HTTP handlers
│   ├── service/              # Business logic
│   ├── middleware/            # Auth, logging
│   └── model/                # sqlc generated code
├── templates/
│   ├── layouts/              # Base layouts
│   ├── pages/                # Full page templates
│   └── partials/             # Reusable fragments
├── styles/
│   └── main.css              # Tailwind entry point
├── static/                   # Built CSS, images
├── model/
│   ├── migrations/           # SQL migrations
│   ├── queries.sql           # sqlc queries
│   └── sqlc.yaml             # sqlc config
└── go.mod

Minimal Server

package main

import (
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /{$}", handleHome)

    log.Println("listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}

That’s a production-ready HTTP server. No framework. No dependencies. Read on to learn each piece of the stack.