Advanced Language Features Basics
10 examples to get you started with Advanced Language Features - 7 basic and 3 intermediate.
Prerequisites
- Go 1.26.x or later and a module:
go mod init example.com/advlang. - Create an
assets/folder next to packages that usego:embed. - Build with
go build/go run .; setGOOS/GOARCHto exercise platform files. - Read Beyond the Spec: Embed, Build Modes, and Assembly for the big picture.
Basic Examples
1. Embed a single file as string
Bake a config file into the binary at compile time.
package main
import (
_ "embed"
"fmt"
)
//go:embed assets/version.txt
var version string
func main() {
fmt.Println("version:", version)
}//go:embedmust sit immediately above astring,[]byte, orembed.FSvariable.- The path is relative to the source file's directory.
- Changing the file requires a rebuild; there is no hot reload.
Related: //go:embed for Files and Templates - FS and template patterns
2. Embed a directory with embed.FS
Serve multiple files from an in-memory filesystem.
package main
import (
"embed"
"fmt"
"io/fs"
)
//go:embed assets/*
var content embed.FS
func main() {
data, err := fs.ReadFile(content, "assets/hello.txt")
if err != nil {
panic(err)
}
fmt.Println(string(data))
}embed.FSpaths use forward slashes and include the embedded directory prefix.- Use
fs.Subto strip a prefix forhttp.FileServerortemplate.ParseFS. - Hidden files and
..paths are rejected at compile time.
3. Modern build constraint on a file
Compile a file only on Linux.
//go:build linux
package main
import "fmt"
func platform() string { return "linux" }
func main() {
fmt.Println(platform())
}- Prefer
//go:buildover legacy// +buildcomments in new code. - Combine tags with
&&,||, and!(for examplelinux && amd64). - Files without constraints compile on every platform.
Related: Build Constraints & Platform-Specific Files - suffix conventions
4. File suffix for GOOS
Let the toolchain pick main_windows.go vs main_unix.go automatically.
// main_unix.go
//go:build unix
package main
func greeting() string { return "unix" }// main_windows.go
//go:build windows
package main
func greeting() string { return "windows" }// main.go
package main
import "fmt"
func main() {
fmt.Println(greeting())
}- Suffixes like
_linux.goand_amd64.goimply constraints without an explicit line. - Keep shared logic in neutral files; put deltas in tagged files.
- Run
go list -f '{{.GoFiles}}' .to see which files a build selected.
5. Custom tag for integration tests
Gate expensive tests behind -tags integration.
//go:build integration
package myapp_test
import "testing"
func TestLiveAPI(t *testing.T) {
t.Log("runs only with -tags integration")
}- Run with
go test -tags=integration ./.... - CI can use default tags locally and integration tags in a nightly job.
- Document required tags in README or Makefile targets.
6. List available build modes
Inspect what go tool supports on your installation.
go help buildmodego build -buildmode=exe -o bin/app .
file bin/app- Common modes:
exe(default),c-archive,c-shared,plugin,shared. pluginand some modes are OS/arch limited.- Production releases should pin the exact
go buildline in CI logs.
Related: Linker Flags & buildmode Options - mode-by-mode guide
7. Strip debug info with ldflags
Shrink release binaries by omitting symbol tables.
go build -ldflags="-s -w" -o bin/app .
ls -lh bin/app-somits the symbol table;-womits DWARF debug info.- You lose some profiling and debugging convenience on stripped binaries.
- Pair with separate debug builds for incident response when needed.
Intermediate Examples
8. Parse embedded HTML templates
Load templates from embed.FS without disk IO at runtime.
package main
import (
"embed"
"html/template"
"os"
)
//go:embed templates/*.html
var tplFS embed.FS
func main() {
tpl, err := template.ParseFS(tplFS, "templates/*.html")
if err != nil {
panic(err)
}
_ = tpl.Execute(os.Stdout, map[string]string{"Name": "Go"})
}ParseFSglob paths are relative to the FS root you embedded.- Ship partials and layouts in the same embed tree for small services.
- For hot reload in dev, keep a filesystem fallback behind a build tag.
9. Go declaration plus assembly stub
Call assembly from Go in the same package (illustrative add).
// add.go
package main
import "fmt"
func add(x, y int64) int64
func main() {
fmt.Println(add(3, 4))
}// add_amd64.s
TEXT ·add(SB), NOSPLIT, $0-24
MOVQ x+0(FP), AX
ADDQ y+8(FP), AX
MOVQ AX, ret+16(FP)
RET- The Go prototype must match the assembly signature;
·names the Go symbol. - Assembly is architecture-specific; provide pure Go fallback for other arches.
- Profile before maintaining
.sfiles; most code should stay in Go.
Related: Assembly in Go (*.s files) - calling conventions
10. Compiler directive for benchmark stability
Prevent inlining when measuring call overhead.
package bench
//go:noinline
func Work() int {
return 42
}//go:noinlineis for tests, benchmarks, and rare ABI boundaries.- Do not sprinkle directives to "help" the optimizer in production without evidence.
- Prefer
go test -benchand profiles before micro-tuning.
Related: Compiler Directives: //go:noinline, linkname & go:fix inline - full directive set
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).