Use when working on the core/ package of inertia-go. Covers architecture, package boundaries, prop system, middleware, context conventions, and testing patterns for the Inertia.js Go adapter.
Guidance for working on the core/ module of inertia-go, the Go server-side adapter for Inertia.js.
core/Always, Defer, Once, Optional, Merge, Scroll)Run from the repo root:
cd core && go build ./...
cd core && go test ./...
cd core && go test -race ./...
cd core && go vet ./...
make format
make tidy
Formatting runs through Docker Compose via go-fmt.compose.yaml. Do not use gofmt directly.
httpx <- leaf foundation (types, headers, context, form parsing)
props <- prop wrappers + resolver (imports httpx)
response <- page object + rendering (imports httpx)
config <- YAML/env config loading via viper (imports httpx)
cryptox <- AES-256-CBC encryption (standalone)
wayfinder <- named route registry + codegen (standalone)
validation <- struct validation via go-playground/validator (imports httpx)
i18n <- URL-prefix locale detection (imports config, httpx)
middleware <- Inertia protocol, CSRF, precognition (imports httpx, config, cryptox)
inertia <- hub: ties props, response, middleware, config together
flash <- flash messages (imports inertia and calls inertia.SetProp)
assert <- test helpers (imports inertia)
Dependency rule: httpx is the shared foundation. inertia is the hub. Do not create circular imports.
In inertia/inertia.go -> mergeProps():
shared < context (SetProp) < render-time < validation errors
Later sources override earlier ones for the same key.
Wrappers compose by struct nesting such as Always(Defer(value)). The resolver in props/resolver.go -> walkPropChain() walks the chain, and the outermost wrapper wins when duplicate traits appear.
httpx.ctxKey for cross-cutting concerns such as CSRF tokens, locale, and precognition.inertia.contextKey for render-scoped data such as props, template data, validation errors, head metadata, and history flags.inertia re-exports SetCSRFToken, SetPrecognition, and SetLocale as convenience wrappers over httpx.
props.Resolve() runs two stages:
Lazy props must not execute during filtering.
config/ loads in this order: defaults, YAML file, then INERTIA_* env vars. Empty Content values in head meta tags act as placeholders and are omitted from rendered HTML.
response.Page JSON tags must match the Inertia.js page object spec. Do not rename tags or add omitempty to required fields without checking the client contract.
testing and net/http/httptestt.Parallel() where safehttptest.ResponseRecorder for HTTP assertionsassert.AssertFromHandler() when tests should exercise middleware and serialized Inertia responsestesting.TB and call t.Helper()validation.Validate() resolves field names as json tag, then form tag, then the Go field namemake format before committingcd core && go test -race ./... for CI-aligned coverageresponse.Page JSON tags in sync with the protocolinertia from httpx, props, response, config, cryptox, or wayfinderomitempty on required response.Page fieldsgofmt directly instead of make formatcore/ currently relies on only two non-stdlib packages:
go-playground/validator/v10 in validation/spf13/viper in config/Keep the dependency surface small.