Architecture¶
goboot is a code generator, not a runtime container. Work flows through a fixed pipeline; each stage is a package decoupled from the next by an intermediate model.
annotation/— lexer + parser for the@Name(arg=value, ...)comment language. Each annotation has a registered schema (valid targets, argument types, defaults) used for validation. Parsers never panic on arbitrary input.compiler/— loads packages viago/packages, associates comments with declarations, and does type analysis withgo/types. Type matching usestypes.Implements(checking bothTand*T) — never string comparison.model/— the intermediateApplicationmodel (components, controllers, routes, repositories, advice, …). It depends on no concrete router or DB.graph/— the dependency graph (consumer → dependency), topological sort for construction order, cycle detection, reverse-order shutdown.generator/di/— emits Go source, then runsgo/format+imports. Output is deterministic and written atomically.runtime/— the small set of reusable abstractions the generated code depends on (lifecycle, HTTP binding,Problemerrors, transactions, observability). It is not a container.
Non-negotiable invariants¶
| Invariant | Meaning |
|---|---|
| Compile-time only | No runtime package scanning or global service locator. |
| Determinism | Same input → byte-identical output. Generators sort everything and avoid timestamps. |
Type safety via go/types |
Interface satisfaction and dependency compatibility are decided by the type checker. |
| Constructor injection | Prefer NewXxx(...) *Xxx / (*Xxx, error) / interface returns. |
| Diagnostics, not panics | User/annotation errors surface as source-positioned Diagnostics with stable GOB* codes. |
Generated output¶
Generated files carry // Code generated by goboot. DO NOT EDIT., use the
zz_goboot_*.gen.go naming, and land in your configured output package
(default internal/generated). They are meant to be committed and read — there
is no magic at runtime.
goboot generate removes its own prior output before loading, so a breaking
interface change never blocks its own regeneration.