xx
.md

Go Examples

These examples pin Go 1.26.5. Replace it deliberately when the project changes toolchain versions.

Build One Source File

Project layout:

.
|-- .xx/
|   `-- build.star
|-- go.mod
`-- main.go

.xx/build.star:

load("@go@1.26.5", "go_binary")

go_binary(entry_point="main.go")

Run xx run build. Output is .xx/out/main or .xx/out/main.exe on Windows.

Build a Package Directory

Use a directory when a command has multiple Go files:

load("@go@1.26.5", "go_binary")

go_binary(
    entry_point="cmd/server",
    output="bin/server",
)

xx invokes go build for the complete cmd/server package and creates bin/ when needed. Custom output names are exact, so use bin/server.exe explicitly when a custom Windows filename is required.

Reproducible Release Flags

Pass normal go build flags through flags:

load("@go@1.26.5", "go_binary")
load("@os@1", "env_set")

go_binary(
    entry_point="cmd/server",
    output="dist/server",
    flags=[
        "-trimpath",
        "-ldflags=-s -w",
    ],
    deps=[env_set("CGO_ENABLED", "0")],
)

Use output for the destination. Do not put -o in flags.

Run Tests with Managed Go

Load the go dependency when a command needs the managed SDK outside go_binary:

load("@go@1.26.5", "go")
load("@os@1", "env_set", "run")

run(
    ("go", "test", "./..."),
    deps=[
        go,
        env_set("CGO_ENABLED", "0"),
    ],
)

No global Go executable is used. The command runs from project root with xx's managed SDK and caches.

Run a Versioned Go Tool

Use go_run for a Go command that does not need to remain available to later tasks:

load("@go@1.26.5", "go_run")

go_run(
    package="codeberg.org/tsukinoko-kun/doctopus",
    version="latest",
    args=["build"],
)

xx invokes go run codeberg.org/tsukinoko-kun/doctopus@latest build with the managed SDK.

Build and Test Together

One entrypoint can declare independent tasks:

load("@go@1.26.5", "go", "go_binary")
load("@os@1", "run")

run(("go", "test", "./..."), deps=[go])

go_binary(
    entry_point="cmd/server",
    output="bin/server",
    flags=["-trimpath"],
)

Both tasks share setup for Go 1.26.5 and may execute concurrently. If one fails, xx cancels the other and exits with an error.

Separate Build and Test Entrypoints

For commands that should be selectable independently, create .xx/build.star and .xx/test.star.

.xx/build.star:

load("@go@1.26.5", "go_binary")

go_binary(entry_point="cmd/server", output="bin/server")

.xx/test.star:

load("@go@1.26.5", "go")
load("@os@1", "run")

run(("go", "test", "./..."), deps=[go])

Run either or both:

xx run build
xx run test
xx run build test

When multiple names are passed, xx starts each entrypoint and reports any failures together.