Skip to content

Getting started

Install

go install github.com/zombocoder/goboot/cmd/goboot@latest

Requires Go 1.25+. Verify:

goboot version

Scaffold

In your module:

goboot init

This writes a goboot.yaml:

application:
  name: my-service
  packages:
    - ./internal/...
generation:
  output: internal/generated
  package: generated
  clean: true
  dialect: postgres

A first app

goboot works well with clean-architecture layering: domain → repository → service → controller, each depending inward through an interface.

package domain

type Todo struct {
    ID    string
    Title string
    Done  bool
}
package repository

// @Repository(generate=true, entity="Todo", table="todos")
type TodoRepository interface {
    // @Exec(`INSERT INTO todos (id, title, done) VALUES (:t.ID, :t.Title, :t.Done)`)
    Insert(ctx context.Context, t domain.Todo) error

    // @Query(`SELECT id, title, done FROM todos WHERE id = :id`)
    FindByID(ctx context.Context, id string) (*domain.Todo, error)
}
package service

type TodoUseCase interface {
    Create(ctx context.Context, title string) (*domain.Todo, error)
}

// @Service(name="todoService", implements="TodoUseCase")
type TodoService struct{ repo repository.TodoRepository }

func NewTodoService(repo repository.TodoRepository) *TodoService {
    return &TodoService{repo}
}

// @Transactional
func (s *TodoService) Create(ctx context.Context, title string) (*domain.Todo, error) {
    t := domain.Todo{ID: uuid.NewString(), Title: title}
    return &t, s.repo.Insert(ctx, t)
}
package controller

// @RestController
// @RequestMapping(path="/todos")
type TodoController struct{ todos service.TodoUseCase }

func NewTodoController(todos service.TodoUseCase) *TodoController {
    return &TodoController{todos}
}

// @PostMapping(path="")
func (c *TodoController) Create(ctx context.Context, req CreateRequest) (*domain.Todo, error) {
    return c.todos.Create(ctx, req.Title)
}
package app

// @Application(name="todo")
type Application struct{}

Generate

goboot generate ./...

goboot writes internal/generated/zz_goboot_wiring.gen.go, exposing NewApplication(...), RegisterRoutes(...), and buildComponents(...). It constructs your components in dependency order, generates the SQL repository implementation, and applies the @Transactional interceptor through a generated proxy.

Reproducible builds

Add a directive so go generate keeps the wiring in sync:

//go:generate go run github.com/zombocoder/goboot/cmd/goboot generate ./...

Wire and run

In cmd/server/main.go, hand goboot the concrete infrastructure — for PostgreSQL via the pgx adapter:

pool, _ := pgxpool.New(ctx, dsn)
dbProvider := pgxadapter.NewProvider(pool)

proxyDeps := runtime.DefaultProxyDependencies()
proxyDeps.Transactions = pgxadapter.NewTransactionManager(pool) // enables @Transactional
httpDeps := runtime.DefaultHTTPHandlerDependencies()

app, _ := generated.NewApplication(proxyDeps, dbProvider, httpDeps, ":8080")
_ = app.Run(ctx) // serves HTTP, graceful shutdown
go run ./cmd/server

That's it — you now have a running service whose wiring is plain, readable, version-controllable Go.

Next: the developer guide and the annotation reference.