Skip to content

Generated Code

Anvil writes ordinary Go into the configured output file.

generator:
output: ./internal/anvil/anvil_autogenerated.go
package: anvilgen

Generated files are compiler output. The next anvil generate run overwrites the configured output file.

Depending on the protocols present in the project, generated code can include:

  • Component structs used by generated wiring
  • Provider registration
  • Provider resolution calls
  • Cycle-safe dependency graph construction
  • HTTP route registration
  • WebSocket route registration
  • Request binding functions
  • Request validation functions
  • Request-level Validate(ctx sdk.Ctx) error calls
  • Middleware chain construction
  • Service registration metadata for gRPC
  • GraphQL endpoint registration metadata
  • Queue job registration metadata
  • Optional package self-registration through init

Generated code uses readable function names and comments around major sections so a developer can debug it without learning compiler internals.

The generated file starts with // Code generated by anvil; DO NOT EDIT. and then exposes two important entrypoints:

func init() {
anvil.RegisterWiring(Wiring())
}
func Wiring() anvil.WiringFunc

The init function supports blank-import wiring. Wiring() supports explicit wiring.

anvil.RegisterWiring returns a cleanup function for tests, but generated packages intentionally ignore it. A generated package self-registers when it is imported, then app.Wire() consumes the registered wiring functions. If application code passes explicit wiring functions to app.Wire(...), only those functions run.

app.Wire() takes a snapshot of the registered wiring functions at the time it runs. Calling app.Wire(anvilgen.Wiring()) bypasses the package-level registry and executes only the supplied function. Passing a nil wiring function returns an error, and calling Wire twice returns anvil.ErrAlreadyWired.

The generated boot function follows the same shape in every generated package:

  1. Register generated DI providers.
  2. Resolve the protocol transports from *anvil.WireContext.
  3. Resolve generated components from DI.
  4. Register HTTP, WebSocket, gRPC, GraphQL, and queue metadata with drivers.

If a project has no routes for one protocol, that protocol registration section can be empty or absent. Generated code wires metadata; drivers execute requests.

Generated files name the provider registration section registerHTTPProviders. That function registers all generated component constructors in the package, not only HTTP controllers. In a mixed package it can install middleware, GraphQL endpoints, gRPC services, queue jobs, bundles, and HTTP controllers before any protocol metadata is registered.

The generated Go file does not embed the route manifest JSON. Tooling reads the same compiler model through anvil manifest, anvil openapi, and anvil testbed. That keeps runtime wiring focused on application startup while tooling keeps its own deterministic output.

Hand-written code registers dependencies through the public app/provider API. Generated provider keys are compiler output and can move when source changes.

Register hand-written dependencies through the public app/provider API:

app := anvil.New(driver,
anvil.WithProviders(
anvil.As[project.Store](project.NewPostgresStore(db)),
anvil.Named[project.Store]("audit", auditStore),
),
)

Use named providers when two dependencies have the same Go type but different roles.

Provider key variables in generated code are for generated wiring only. The key string is based on Go package, type name, and optional provider name, but the variable names and grouping are compiler output. Treat them like any other generated implementation detail.

Explicit wiring keeps generated modules visible at the call site:

import "example.com/portal/internal/anvilgen"
if err := app.Wire(anvilgen.Wiring()); err != nil {
return err
}

This is the best default for tests and applications with multiple generated modules.

Generated packages can self-register:

import _ "example.com/portal/internal/anvilgen"
if err := app.Wire(); err != nil {
return err
}

Use this when the app shell intentionally wants generated modules to register through package initialization.

When a route behaves incorrectly:

  1. Run anvil generate.
  2. Open the generated file.
  3. Search for the controller and endpoint name.
  4. Inspect the generated route registration.
  5. Inspect the generated request binder.
  6. Inspect the generated validation function.
  7. Inspect the middleware chain around the handler.
  8. Compare the route with anvil manifest.

If the generated code is difficult to read, that is an Anvil bug. Generated code is part of the developer experience.

With identical source, config, and Go toolchain inputs, generated code stays stable. Stable output keeps code review meaningful and makes generated-file diffs useful.

Deterministic output makes generated diffs reviewable when route tables, request models, middleware, providers, or config change.