Getting Started

Your first module

Generate a module, run the codegen chain and boot the service.

This page plays out the first step of the shop sample application: from an empty project to a booting module serving requests.

Generate the module

go tool gpsystem new module shop

This creates:

  • the entry point (cmd/shop/main.go): a server.Run call wired to a RegisterFunc;
  • the surface wiring (internal/modules/shop/surfaces/register.go, package surfaces): a Dependencies struct + an exported RegisterApi(router, deps) function;
  • an api surface under surfaces/api/: a handler bound to the generated strict interface, a minimal service/ seam, a policy/ registry stub, plus a kept-empty http/mapper/ folder for your own code;
  • the module-level shared skeletons: the module root package (shop.go + errors.go, package shop: home of the rules and sentinel errors the surfaces share) and repository/ (the module's single persistence layer);
  • the TypeSpec contract (spec/typespec/modules/shop/) and the codegen config (api/oapi-codegen/shop-api.yaml);
  • then registers everything via anchor insertions (main.tsp, cmd/shop/main.go).

Run the codegen chain

mise run generate

This compiles TypeSpec to OpenAPI (api/openapi/), runs oapi-codegen with the project's template set (upstream chi-server plus the framework's strict overrides), places the output under internal/modules/shop/surfaces/api/http/gen/, tidies and builds. The sample handler implements the generated strict interface, so the project compiles immediately: spec/code drift is a compile error.

Boot it

go run ./cmd/shop

Try it

curl localhost:3000/api/v1/shop/

The scaffold handler returns an empty list; replace its body once you've built the module's root package and repository/ layer, with the surface's service/ seam serving from them.

Errors are RFC 9457 problem documents by default (Error responses):

curl localhost:3000/api/v1/nope

Press Ctrl+C: the server waits out in-flight requests, closes the pool, flushes telemetry and exits cleanly. That's the app lifecycle at work, which server.Run sits on.

During development it's worth switching on the Monolog-style console log (LOG_FORMAT=monolog): you'll see error chains in the readable format you know from PHP.

Where to next

From here you can follow the path of the shop sample application:

Copyright © 2026