Skip to main content
eLearner.app
Module 9 · Lesson 5 of 545/50 in the course~10 min
Module lessons (5/5)

Build constraints and tags

Build constraints (also called build tags) gate the compilation of a file based on OS, architecture, Go version or custom tags passed on the command line. They are used for cross-platform code, opt-in heavy test files, and similar scenarios.

Modern syntax: //go:build

Since Go 1.17+ the canonical format is the special //go:build comment, placed at the top of the file before package, on a line by itself, followed by a blank line:

Go
//go:build linux

package main

// this file is built ONLY on Linux

Three absolute rules:

  1. The comment must appear before package.
  2. It must be followed by a blank line.
  3. No space between // and go:build (it is a syntactic trigger, not just any comment).

Boolean expressions

The expression after //go:build accepts logical operators:

Go
//go:build linux && amd64           // both conditions
//go:build linux || darwin          // any one (Unix-like)
//go:build !windows                 // negation
//go:build (linux || darwin) && !arm64
//go:build go1.22                   // Go version ≥ 1.22
//go:build integration              // custom tag (see below)

The most common built-in tags:

  • OS: linux, darwin, windows, freebsd, js...
  • Architecture: amd64, arm64, 386, wasm...
  • Go version: go1.20, go1.22... (true if the version is ≥).
  • cgo: true if cgo is enabled.

Cross-platform: filename convention

Beyond explicit tags, Go recognises filename suffixes as implicit build constraints:

Code
db_linux.go         // linux only
db_windows.go       // windows only
db_linux_amd64.go   // linux/amd64 only

It is the idiomatic pattern for platform-dependent implementations of the same interface (each file defines the same functions with different code).

Custom tags: opting into heavy tests

Custom tags are any identifier you pass on the command line:

Go
//go:build integration

package mypkg

// tests that need a real DB, run only on demand

Execution:

Bash
go test -tags=integration ./...

Without -tags=integration, the file is invisible to the compiler (the tests inside it do not exist for go test). It is the canonical way to separate unit tests (always) from integration tests (on demand, maybe only in CI).

Old syntax: // +build (deprecated)

Before 1.17 the format was // +build linux (note the space, and that it is +build, not go:build). It is still supported for backward compatibility, but gofmt in Go 1.17+ adds both when it only finds the old one:

Go
//go:build linux
// +build linux

package main

For new files use only the modern //go:build form.

Exercises

Exercise#go.m9.l5.e1
Attempts: 0Loading…

At the top of the file add the build constraint that compiles it ONLY on Linux. Remember the blank line before package.

Loading editor…
Show hint

The //go:build comment goes BEFORE package, on a line by itself, followed by a blank line.

Solution available after 3 attempts

Exercise#go.m9.l5.e2
Attempts: 0Loading…

Add a build constraint that EXCLUDES Windows (use the negation operator !).

Loading editor…

Solution available after 3 attempts

Quiz#go.m9.l5.e3
Ready

To enable at test time a custom 'integration' tag declared with //go:build integration, which flag do you use?

Go
$ go test -tags=???
Answer options