Skip to content
Spice Framework on GitHub

Getting started

frameworkMaturity: previewSource: spice@c0641b3Exact reviewed source

This guide builds and runs the Petclinic reference application using ordinary Go source and inspectable generated Go. It requires Go 1.26.5. No database, container, or network download is needed after the application’s declared module and tool dependencies are present.

Authorize the CLI

From the consuming application’s module, select compatible toolchain versions with ordinary Go commands:

go get -tool github.com/spice-framework/toolchain/cmd/spice@<version>
go get -tool github.com/spice-framework/toolchain/cmd/spice-annotation-core@<version>
go tool github.com/spice-framework/toolchain/cmd/spice version

The application’s go.mod authorizes the executable dependencies. Core does not build or download the CLI, and Spice does not maintain a second plugin dependency system. Release archives are produced by the toolchain repository’s exact-tag process described in releasing.md.

Create a clean application

spice new creates a valid-Go application and its ordinary go.mod without running a Go command, downloading a module, initializing Git, or overwriting a non-empty directory:

spice new --module example.com/acme/hello --directory hello
cd hello
go mod download
go tool github.com/spice-framework/toolchain/cmd/spice generate --target Hello .
go tool github.com/spice-framework/toolchain/cmd/spice verify .
go tool github.com/spice-framework/toolchain/cmd/spice run --target Hello .

The target name and generated-package ID derive from the final module-path segment through the same compiler-owned normalization used during analysis. Initial generation supplies the missing generated package through an in-memory overlay; no physical stub is created. Run go mod tidy after that first generation. --spice-version selects an exact pre-release or release when the CLI build should not select its own version. --replace is an explicit local development option and is never emitted by a release workflow by default.

Add an ordinary dependency through a previewed standard Go operation:

spice add golang.org/x/sync/errgroup@v0.22.0
spice add --apply golang.org/x/sync/errgroup@v0.22.0

The first command runs go get only against a temporary sibling modfile and prints the exact bounded go.mod/go.sum diff. --apply creates a fresh plan, prints it, and writes its exact after-images only while both original file hashes still match. Add --tool to use Go’s go get -tool authorization path. These commands are explicit network-capable developer actions; normal analysis, generation, and editor operation remain offline and read-only.

Inspect the application

Petclinic is an independent consumer module at spice-framework/petclinic. Clone it separately from the core framework. Its go.mod selects an immutable Spice version, authorizes the CLI and annotation tool with standard Go tool directives, and contains no local replace:

git clone https://github.com/spice-framework/petclinic.git
cd petclinic
go tool github.com/spice-framework/toolchain/cmd/spice verify .
go tool github.com/spice-framework/toolchain/cmd/spice generate --check --target Petclinic .

The process entrypoint in main.go is valid Go:

// @import { Application } from "github.com/spice-framework/spice/annotation/core"
// @import { Enable } from "github.com/spice-framework/spice/annotation/management"
// @Application
// @Enable(expose=["health", "readiness", "info"], access="loopback")
func main() {
os.Exit(spiceapp.Main(os.Args[1:]))
}

@import is file-scoped and explicit. The imported descriptor is a real Go function that the compiler decodes without executing. The target module’s go.mod is the only authority that permits its handler tool to run. spiceapp is the ordinary Go import alias for github.com/spice-framework/petclinic/internal/spicegen/petclinic.

Verify and generate

From the standalone Petclinic root, use its authorized Spice tool dependency:

go tool github.com/spice-framework/toolchain/cmd/spice verify .
go tool github.com/spice-framework/toolchain/cmd/spice generate --check --target Petclinic .

generate --check is read-only. To create or update owned artifacts, run the same command without --check. The output has three clear roles:

internal/spicegen/petclinic/spice_assembly_gen.go
bounded construction-phase sequencing
internal/spicegen/petclinic/spice_{contracts,configuration,providers}_gen.go
typed contracts, configuration metadata, and dependency construction
internal/spicegen/petclinic/spice_http_gen.go
HTTP and management coordination
internal/spicegen/petclinic/spice_http_route_<symbol>_<id>_gen.go
one stable, source-linked route adapter
internal/spicegen/petclinic/spice_{features,lifecycle,command}_gen.go
optional features, reusable lifecycle, and process entrypoint behavior
internal/spicegen/petclinic/sources/<package>/<source>_spice_gen.go
one source-owned unit with direct construction, binding, and assertions
internal/spicegen/petclinic/artifacts/openapi.json
generated non-Go contracts
.spice/petclinic.manifest.json
hashes, roles, source origins, and generated ranges

Generated files are committed, formatted Go. The ownership manifest prevents Spice from overwriting manual edits or unrelated files. Run go tool github.com/spice-framework/toolchain/cmd/spice generated --source main.go to locate the source-owned application unit, or pass that generated path with --generated for the reverse mapping.

Run and debug

Start the application:

Terminal window
$env:SPICE_PETCLINIC_ADDRESS = "127.0.0.1:8080"
go tool github.com/spice-framework/toolchain/cmd/spice run --target Petclinic .
Terminal window
SPICE_PETCLINIC_ADDRESS=127.0.0.1:8080 \
go tool github.com/spice-framework/toolchain/cmd/spice run --target Petclinic .

Open http://127.0.0.1:8080/. Search owners, edit an owner, add a pet and a visit, and inspect /vets. Management routes under /actuator/ accept only a direct loopback peer.

spice run generates safely and then builds the complete package with -trimpath; it never compiles a temporary source fragment. A Go debugger sees normal generated calls and steps directly into handwritten constructors, controllers, and repositories. The GoLand plugin uses this complete-package path for Run and generates before native Go/Delve Debug.

Use the development loop

Replace run with dev. Spice watches relevant files, debounces changes, and gracefully replaces the process only after analysis, generation, and build succeed:

go tool github.com/spice-framework/toolchain/cmd/spice dev --target Petclinic .

Add // @Unknown below // @Application and save. The compiler reports an exact diagnostic while the last-known-good process remains live. Remove the invalid annotation and save; Spice regenerates and restarts the package.

Test a generated application

Use ordinary Go tests for domain code. For generated wiring, create a typed context with spicetest.NewContext; for routes, use spicetest.NewHTTP; for database behavior that must roll back, use spicetest.NewSQL. These helpers accept typed generated applications and never use reflection, provider replacement, or a runtime container.

Focused module tests retain ordinary Go controls:

go tool github.com/spice-framework/toolchain/cmd/spice test --module example.com/shop/orders --race --count=1 ./...

See testing.md for complete examples and cleanup behavior.

Next steps