Go Compile-Time Variable Injection: Using go build -ldflags -X

Background
While working on a company project recently, I looked into whether there is a way to inject variables at compile time without a .env file.
I thought this would be very convenient, since only a single file would be needed without any .env or multiple config files.
At first, I searched for a go:generate CLI or something similar that generates a constants file based on .env, but I could not find one.
However, if I were going to do that, I could just modify the constants directly without bothering to run a generator, and I found that there is a way to inject values at compile time, similar to the include_bytes! macro in Rust.
Compile-Time Variable Injection
The usage is simple.
1package main
2
3import "fmt"
4
5var Foo string
6
7func main() {
8 fmt.Println(Foo)
9}
Given code like the above, you can inject a value at build time as follows.
1go build -ldflags="-X 'main.Foo=bar'"
By passing the argument through ldflag, the value bar is injected into the Foo variable at compile time during the build. It is simple.
If there are variables or packages with the same name in multiple places in the project, you can specify the package path.
1// github.com/myproject/config/config.go
2package config
3
4var Version string
5
6// github.com/myproject/internal/config/config.go
7package config
8
9var BuildTime string
In such cases, you can inject them separately as follows:
1go build -ldflags="-X 'github.com/myproject/config.Version=v1.0.0' -X 'github.com/myproject/internal/config.BuildTime=2025-05-27'"
Even when multiple variables exist in the same package, you simply pass additional arguments.
1go build -ldflags="-X 'main.Version=v1.0.0' -X 'main.BuildTime=2025-05-27' -X 'main.GitCommit=abc123'"
The characteristics are as follows:
- The variable does not need to be public: variables starting with a lowercase letter can also be injected
- Only string type is supported: other types are not supported