Blog
Using Flox to Create Portable, Reproducible Go Environments
Steve Swoyer | 10 October 2024
Flox makes it easy to create portable, reproducible Golang (Go) dev environments that run the same way on Linux, macOS, and Windows (with WSL2), across both ARM and x86 architectures.
And if you've got an existing Go project with a go.mod
file, it's just as easy to use it with Flox. You won’t even have to do much lifting, because Flox automatically installs Go for you!
This article provides a quick-start overview of how to create Flox environments for new Go projects, and showcases how Flox integrates with existing Go projects, too. It also explores the benefits of using Flox to create, share, and manage your Go dev environments.
Beyond portability and reproducibility, Flox supports all languages and toolchains, which makes Flox dev environments ideal for Go projects involving C libraries, JavaScript runtimes, Python, and other languages. And unlike containers, Flox environments give you transparent access to all your local resources—including aliases, environment variables, tools, and editors—in addition to strict deterministic safeguards, so your Go builds work consistently over time.
Sound intriguing? Let’s get started!
Kickstarting a New Go Project with Flox
So you're kicking off a new Go project and you want to use Flox.
Smart choice! Flox’s superpower is reproducibility, so the Go dev environments you create on your Linux laptop will Just Work on the macOS and Windows (with WSL2) laptops your teammates use to build locally. And these same Flox environments will also Just Work when you (or your teammates) push them to CI and production.
Best of all, getting started with Flox is super simple! First, just create and/or cd into your project directory and type flox init
to initialize a new Flox dev environment.
This is a Go project, so you need to get Go. No problem! You can just grab it from the Flox Catalog:
The cool thing about Go is that it’s generally backward-compatible from version to version, so you could probably just flox install
the latest. But for argument’s sake, let’s say you need a specific version of Go: v1.21.7. Does the Flox Catalog have that? Let’s find out!
You can use flox show
to see which go
packages you can get from the Flox Catalog:
The list above is truncated because the Flox Catalog has more than 40 versions of the go
package, stretching back to v1.15.6 (released almost four years ago). But let’s just go ahead and flox install
v1.21.7:
Another great thing about Go is that it’s mostly self-contained. Once you go mod init
to kick off a project, you can get much of what you need from Go’s standard library, and use go mod tidy
to grab the rest.
But if you’re like most Go programmers, you’re probably going to want to pre-build some basic Go tooling into your dev environment, perhaps even pinning these to specific versions to ensure reproducibility and determinism.
You know, stuff like golangci-lint, air, goreleaser, or maybe even gox.
Guess what? You can get all this stuff from the Flox Catalog, too!
You can run flox list
to see which versions of these packages Flox installed in the environment...
...and run flox edit
to view or modify the contents of manifest.toml, the declarative manifest that defines software package versions, environment variables, services, automation logic, and anything else that’s exposed via a Flox environment. This file lives inside the .flox
directory nested inside every environment. (You can also modify it using your preferred editor.)
Here’s the [install]
section of this Flox environment’s manifest.toml
:
You can use the <package_name>.version =
syntax to pin specific package versions, like v1.21.7 of the go
package. For instance, if you want to pin goreleaser
to v1.24.0, you would just add the following line in the manifest's [install]
section:
That’s it! Flox is also a genius at resolving package dependencies, and gives you simple, declarative methods for installing just the right packages.
Now that you’ve got your environment squared away, it’s time to fire it up with flox activate
:
Simple, right?
Flox isn’t a replacement for your preferred Go workflow, or for configuration artifacts like go.mod
files, which go mod init
creates to define your project’s path and dependencies. Instead, it simplifies, complements, and accelerates your Go dev workflow.
You can use Flox to create a portable, reproducible Go dev environment that runs anywhere. An environment your team can use to build locally—with standard, built-in versions of essential Go tools, starting with the Go compiler and toolchain—push to CI, and deploy in prod. Flox also gives you a simple, declarative way to define environment variables, settings, services, and overrides for your Go dev environment, which makes it easy to customize environments for each project. Finally, Flox is a slam-dunk for enabling hybrid projects that depend on tools and libraries from outside Go’s ecosystem.
Integrating Flox with Existing Go Projects
But what if you want to use Flox with an existing Go project—like a GitHub repo that defines its package dependencies using a go.mod
file? No problem! Whether you're just starting from scratch or you need to integrate with an existing project, Flox is the first-class solution for creating portable, reproducible, declarative Go dev environments that Just Work … anywhere.
Let’s use etcd, the Cloud Native Computing Foundation’s distributed key-value store, as an example project.
You can clone etcd from GitHub and build it in a Flox environment without breaking a sweat.
So let’s do that! First, we’ll clone the repo:
Then we’ll initialize a new Flox environment in the project directory:
Interesting! Flox detected a go.mod
file, so it automatically prompted us to “apply the standard Go environment." The first thing to note is that you can Just Say "No" to this prompt, if you prefer to go mod init
and bootstrap your Go dev environment yourself.
The second thing is that you can select “Show environment manifest” to see what, exactly, Flox proposes to do:
The text above shows the pending contents of our Floxified etcd environment’s manifest.toml
.
In this case, Flox parsed the go.mod
file in the etcd project directory, identified the required go
package, and automatically added it to Flox’s software manifest. The caret (^
) means Flox will install any version of Go equal to or greater than v1.22 but less than v2.0 (which doesn’t yet actually exist). This is basic SemVer notation, using SemVer's caret range operator, or ^
. You can use other SemVer operators, too.
Separately, the [hook]
section defines activation hooks that run whenever you flox activate
the environment, setting the required variables and installing dependencies defined in the project's go.mod
file.
You can click "Yes" to accept these changes, or "No" if you prefer to implement some or all of this stuff yourself.
That’s basically it. We’ve got everything we need to build and run our portable, reproducible etcd dev environment. So let's run flox activate
and do that!
The first time we activate this environment, the logic in [hook]
runs go get .
to fetch etcd's 50+ required dependencies. The code block above shows a truncated version of this output. This happens only once, unless we add fresh dependencies to etcd's go.mod
file.
OK. Now that we’ve activated the Flox environment and installed all our required dependencies, we’re ready to build etcd.
Excellent. The etcd build completed successfully! But let's not start celebrating just yet: we still have some set up work to do.
For one thing, we need to set a PATH
env var for etcd to work properly. The project docs tell us to just export this via the command line, or to add it to .bashrc
, .zshrc
, etc., but we can do better than this! Let’s define it as part of our Flox environment; that way it’s preconfigured for anyone we share it with. Ordinarily, we’d define this in the [vars]
section of manifest.toml
, but let’s put it in [hook]
, along with our existing Go vars. (Note: [vars]
doesn’t support having one variable referencing another; [hook]
does.)
The [hook]
section in our etcd environment’s manifest.toml
now looks like this:
The next thing we need to do is to configure etcd to run as a service. Flox's service management capabilities make this simple!
We use [services.<name>]
to define each service, using the command =
syntax to configure a start-up command and any required parameters. We could start the etcd
bin with command = “etcd”
, but it probably makes sense to define a custom persistence directory (--data-dir ./etcd-data
), as well as specify other user-customizable parameters, like listening and advertising addresses. This done, we can either run etcd
manually, type flox services start
, or exit our environment and re-start it using flox activate -s
. Let’s exit and restart:
It sure looks like etcd started up. But let’s confirm:
Success!
The Flox Catalog has millions of software package and version combinations, which comes in handy when you’re working on a project and need just the right tool. For example, if you were building an etcd container for deployment on Kubernetes (K8s), you could flox install
ko, kind, and kubectl to run and test your container on a local K8s cluster. Once done, you’d push it to your container registry, where it could be pulled by your Kubernetes clusters in CI and prod.
With Flox, you could easily bake this workflow into a reproducible dev environment that can be used by your whole team!
Flox Lets You Pass Go Faster
Flox makes it trivially easy to create and share portable, reproducible Go development environments.
When teams integrate Flox into their workflows, they accelerate the rate at which they build and ship software. Flox and the Flox Catalog give them just one place to get what they need, along with powerful declarative tools for configuring and managing their Go environments.
Plus, Flox environments run in the local system context, so teams get transparent access to the files, tools, and settings on their machines. Best of all, a Flox Go environment created using an ARM-based MacBook Pro runs without a hiccup on the Windows (with WSL2) and Linux laptops used by others on the team. Even better, this environment runs the same when you push it to CI or deploy it to prod!
It's simple to get started using Flox. In less than five minutes, you can set up a Go dev environment on your laptop. To share your environment, just run git push
or flox push
(to push to FloxHub).
That's all it takes! Your teammates can git clone
or flox pull
your Go environment to run it locally.
Download Flox today and transform your Go workflow!