All images in this article are AI-generated by the author with NightCafe Studio.
Introduction
Go, often referred to as Golang, has earned its distinguished reputation through a combination of elegant simplicity, raw performance, and powerful concurrency models.
A truly transformative, yet often understated, feature of Go is its innate and robust support for multiplatform programming.
The ability to write a single codebase and compile it for a diverse landscape of operating systems and architectures with minimal effort is a paradigm shift for developers.
This guide provides a deep dive into using Go for cross-platform development, covering desktop and mobile targets, including:
- Windows
- Linux
- macOS
- Android
- iOS
- And many more!
The Core Principle: GOOS
and GOARCH
At the very heart of Go's cross-compilation magic are two fundamental environment variables: GOOS
and GOARCH
.
These variables act as simple yet powerful directives for the Go compiler, instructing it on the precise operating system and processor architecture for the intended binary output.
This streamlined approach, a standard feature since Go 1.5, has made a historically convoluted process remarkably straightforward.
GOOS
:- This variable designates the target operating system, with common values like
linux
,windows
,darwin
(the core of macOS),android
, andios
.
- This variable designates the target operating system, with common values like
GOARCH
:- This variable specifies the target processor architecture, with popular choices being
amd64
(for 64-bit x86),386
(for 32-bit x86),arm64
(for 64-bit ARM), andarm
.
- This variable specifies the target processor architecture, with popular choices being
To discover the complete matrix of supported platform and architecture combinations for your specific Go installation, you can run a simple diagnostic command.
go tool dist list
This command queries the Go toolchain and prints an exhaustive list of every possible target, demonstrating the vast and versatile reach of the Go compiler.
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
illumos/amd64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
openbsd/mips64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386
windows/amd64
windows/arm
windows/arm64
This stunned me the first time I saw it and still stuns me today!
Golang Tooling and Developer Experience
One of Go's most celebrated features is its integrated and opinionated toolchain, which creates a highly productive and consistent developer experience.
The toolchain is included in the standard Go distribution, requiring no separate installation or complex configuration.
go build
:
- The compiler is famously fast, leading to rapid iteration cycles. It produces single, statically linked binaries by default, simplifying deployment.
go fmt
:
- This tool automatically formats Go code according to a standard convention.
- It effectively ends debates over code style and ensures all Go code, regardless of author, has a similar structure.
go test
:
- Go has a lightweight testing framework built directly into the toolchain, complete with support for benchmarking and code coverage analysis, making testing a first-class citizen.
go mod
:
- Modern Go uses a simple and effective module system for dependency management.
- The
go.mod
file is easy to understand and manage, avoiding the complexity of build systems like Maven or Gradle.
This cohesive set of tools lowers the barrier to entry and allows developers to focus on writing code rather than configuring their environment.
Compiling for Desktop Platforms
Generating executables for traditional desktop environments represents the most direct application of Go's cross-compilation features.
The process yields single, statically-linked binaries with no external runtime dependencies, which simplifies distribution immensely.
Compiling for Windows from Linux/macOS
To produce a self-contained executable file for the Windows platform, you only need to set the GOOS
environment variable to windows
.
For modern 64-bit Windows systems:
GOOS=windows GOARCH=amd64 go build -o myapp-amd64.exe .
For legacy 32-bit Windows systems:
GOOS=windows GOARCH=386 go build -o myapp-386.exe .
The resulting .exe
files can be run directly on any target Windows machine without needing to install a Go runtime, a key advantage for user convenience.
Compiling for Linux from Other Platforms
In a parallel fashion, targeting the Linux operating system is as simple as setting the GOOS
variable to linux
.
You can compile for numerous processor architectures, with amd64
for servers and desktops and arm64
devices like the Raspberry Pi are extremely common.
For 64-bit Linux on x86 architecture:
GOOS=linux GOARCH=amd64 go build -o myapp-linux-amd64 .
For 64-bit Linux on ARM architecture:
GOOS=linux GOARCH=arm64 go build -o myapp-linux-arm64 .
These binaries are ready for immediate execution on any Linux distribution matching the specified architecture.
Compiling for macOS from Other Platforms
To compile an application for macOS, you set the GOOS
variable to darwin
.
The macOS platform has notably transitioned from Intel (amd64
) processors to Apple's custom ARM-based Silicon (arm64
), and Go can target both.
For Intel-based Mac computers:
GOOS=darwin GOARCH=amd64 go build -o myapp-macos-amd64 .
For Apple Silicon-based Mac computers:
GOOS=darwin GOARCH=arm64 go build -o myapp-macos-arm64 .
Creating a Universal Binary for macOS
To distribute a single application that runs natively on both Intel and Apple Silicon Macs, you can create a "universal" binary.
This process requires compiling for both architectures and then merging them with the lipo
command-line tool, which is part of Apple's Xcode development environment.
Step 1: Compile for each separate architecture:
GOOS=darwin GOARCH=amd64 go build -o myapp-amd64 .
GOOS=darwin GOARCH=arm64 go build -o myapp-arm64 .
Step 2: Use the lipo
tool to create the universal file:
lipo -create -output myapp-universal myapp-amd64 myapp-arm64
This single myapp-universal
executable provides the best performance on all modern Macs by containing the native code for both processor families.
Diving into Mobile: Go on Android and iOS
Go's multiplatform capabilities extend into the mobile sphere via the gomobile
tool, a specialized part of the Go ecosystem.
Crucially, gomobile
can be used for building complete, working Golang mobile apps with basic UI capabilities using the golang.org/x/mobile/app package and OpenGL ES.
Setting up gomobile
First, you must install the gomobile
tool and run its one-time initialization command to set up the required bindings and toolchains.
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
For Android, you must have the Android NDK (Native Development Kit) installed.
For iOS, Xcode is required, and the build must be performed on a macOS machine.
Compiling a Go Library for Android
To compile a Go package into a standard Android Archive (.aar
) library, you use the gomobile bind
command.
This command inspects your Go package and generates the necessary Java interface code (the "binding") to make it callable from Kotlin or Java.
gomobile bind -target=android -o greeter.aar .
You can then import this greeter.aar
file into your Android Studio project's libs
folder and add it as a dependency.
This allows you to call your performant Go logic directly from your Android app code.
Compiling a Go Library for iOS
The process for iOS is analogous.
On a Mac, you run gomobile bind
with the ios
target.
This command generates an XCFramework
, the modern, universal format for binary libraries on Apple's platforms.
gomobile bind -target=ios -o Greeter.xcframework .
You can then drag this Greeter.xcframework
directly into your Xcode project.
Swift code can immediately import and use the functions from your Go package.
Go vs. Flutter/Dart for Cross-Platform Mobile Coding
Go and Flutter represent fundamentally different approaches to cross-platform development.
Go shares logic (and more rarely, UI), while Flutter shares both logic and UI.
Feature |
Golang (with gomobile) |
Flutter (with Dart) |
---|---|---|
Primary Use Case |
Sharing non-UI code (business logic, networking, algorithms) as a native library. |
Building complete, self-contained applications with a unified UI from a single codebase. |
UI Strategy |
Limited UI capabilities. Relies entirely on the native UI toolkits of the host platform (e.g., SwiftUI for iOS, Jetpack Compose for Android). |
Provides its own comprehensive UI toolkit. Renders every pixel on the screen using its Skia graphics engine, bypassing native UI widgets. |
Development Paradigm |
Embed a foreign library into a native application. The core app is still native. |
Write the entire application, including the UI, in Dart. The app is a Flutter app. |
Performance |
Excellent for raw computational tasks. The shared library runs as a compiled native binary. |
Excellent UI performance (often 60/120fps). Dart can be JIT compiled for fast development and AOT compiled for fast release builds. |
When to Choose |
When you need to share highly performant, complex logic behind a fully native UI/UX, or when reusing existing Go backend code on mobile. |
When your priority is building an application with a consistent, brand-centric UI across all platforms with maximum code reuse. |
Go vs. Kotlin Multiplatform (KMP) for Cross-Platform Mobile Coding
Go and Kotlin Multiplatform (KMP) are more direct competitors, as both focus on sharing non-UI logic.
However, it must be noted that now Golang has support for GUIs as well.
The primary differences lie in language integration and ecosystem.
Feature |
Golang (with gomobile) |
Kotlin Multiplatform (KMP) |
---|---|---|
Primary Use Case |
Both are used to share non-UI logic between platforms by compiling to native libraries. |
Both are used to share non-UI logic between platforms by compiling to native libraries. |
Language Integration |
Always a foreign language. Communication happens across a bridge (FFI) automated bygomobile. |
Native on Android (Kotlin-to-Kotlin). Excellent interop with Swift on iOS. Feels more like an extension of the native environment. |
Development Paradigm |
Embedding a separate ecosystem (Go) into native apps. |
Extending the Kotlin ecosystem to other platforms. Logic is written in a common main source set. |
Build System |
Extremely simple and fast go build command. |
Relies on Gradle, which is powerful and deeply integrated with Android Studio, but also significantly more complex and slower than Go's tooling. |
Target Breadth |
Excellent, mature support for a vast range of OS/architecture targets beyond mobile (servers, desktops, CLI, WebAssembly). |
Primarily focused on Android and iOS, with desktop and WebAssembly support maturing. Less emphasis on server-side targets. |
When to Choose |
For performance-critical code, targeting a wide array of platforms, or when simplicity of the toolchain is a significant priority. |
For teams heavily invested in the Kotlin ecosystem, especially for sharing logic between Android and iOS, where seamless language integration is key. |
But now, of course, there are tools that allow you to build GUIs in Golang for mobile platforms as well.
Just donโt expect Liquid Glass!
You can find some of them below:
Helpful Go Libraries for UIs, Distribution, and More
While Go's standard library is extensive, the rich third-party ecosystem provides powerful tools that simplify building user interfaces and distributing cross-platform applications. Here are ten valuable libraries that are instrumental in the Go multiplatform ecosystem.
Fyne
- A comprehensive and easy-to-use toolkit for creating graphical user interface (GUI) applications.
- It is written in pure Go and uses a clean, declarative API to build applications that run on desktops (Windows, macOS, Linux) and mobile devices (iOS, Android).
- It follows Material Design principles, ensuring a modern and consistent look and feel across all platforms.
- GitHub: https://github.com/fyne-io/fyne
Wails
- An innovative framework for building desktop applications using Go for the backend logic and modern web technologies (HTML, CSS, JavaScript) for the frontend UI.
- It provides a true alternative to Electron, using native platform web renderers instead of bundling a full browser, resulting in smaller and more performant binaries.
- Allows for easy two-way communication between the Go backend and the JavaScript frontend.
- GitHub: https://github.com/wailsapp/wails
GoReleaser
- The definitive tool for automating the release and distribution of Go projects.
- It streamlines the entire release workflow: it cross-compiles for multiple platforms, creates archives (.zip, .tar.gz), generates changelogs from git history, and can automatically create a GitHub Release.
- It can also publish artifacts to various package managers like Homebrew and Scoop, and build and push multi-arch Docker images.
- GitHub: https://github.com/goreleaser/goreleaser
Cobra
- A powerful library for creating modern command-line applications with a sophisticated command structure.
- It is the foundation for many popular tools like
kubectl
andhugo
, enabling nested commands (e.g.,app server start
), flags, and automatic generation of help text and shell completion scripts. - Its functionality works identically across all platforms, making it ideal for cross-platform CLI tools.
- GitHub: https://github.com/spf13/cobra
Gio
- An immediate-mode GUI library focused on high performance and fine-grained control over rendering.
- Instead of providing pre-built widgets, Gio gives developers the tools to draw custom interfaces efficiently.
- This makes it an excellent choice for data visualization tools, games, and other graphics-intensive applications that need to be portable.
- GitHub: https://github.com/gioui/gio
Viper
- A complete configuration solution for Go applications that works seamlessly across all platforms.
- It can read configuration from a variety of sources simultaneously, including JSON, TOML, YAML, and Java properties files.
- It can also read from environment variables, command-line flags, and remote key/value stores, making it incredibly flexible for configuring applications in different environments.
- GitHub: https://github.com/spf13/viper
Zerolog
- A high-performance, structured logging library that produces zero-allocation JSON logs.
- Structured logging is crucial for modern applications, as it allows logs to be easily parsed and queried by log management systems.
- Its exceptional performance and low overhead make it suitable for any application, and its platform-agnostic nature ensures consistent logging everywhere.
- GitHub: https://github.com/rs/zerolog
GoReleaser/nfpm
- A simple, zero-dependency tool for creating native Linux software packages.
- It can generate
.deb
,.rpm
, and.apk
(Alpine Linux) packages from a single YAML configuration file, without needing tools likedpkg
orrpmbuild
installed. - It's a perfect companion for GoReleaser for projects that require traditional Linux package distribution.
- GitHub: https://github.com/goreleaser/nfpm
Afero
- A filesystem abstraction system for Go, providing an interface that can be backed by various implementations.
- It allows you to write code that interacts with a filesystem without being tied to the host OS's filesystem.
- This is invaluable for testing, as you can easily swap the OS filesystem for a fast, in-memory filesystem, allowing for reliable and platform-independent tests of code that performs file I/O.
- GitHub: https://github.com/spf13/afero
Conclusion
Go's multiplatform capabilities are a testament to its pragmatic design, offering a powerful and refreshingly simple solution for building and distributing software.
Its true strength lies not in replacing native UI development, but in augmenting it.
Go enables developers to write core business logic, complex algorithms, or networking stacks once, in a highly performant and concurrent language, and then deploy that logic everywhere.
Go empowers you to build fully native, platform-idiomatic UIs while sharing the complex, non-visual code that powers them.
The gomobile tool can even help you create complete mobile native apps that have basic UI features.
Go stands out with its unparalleled toolchain simplicity, lightning-fast compiler, and mature support for a vast spectrum of platforms beyond just mobiles.
By mastering Go's cross-compilation tools, developers gain a potent new strategy in their arsenal, enabling a hybrid approach that combines the performance of native code, the UX of native interfaces, and the efficiency of a shared cross-platform core.
Go is not just a language; it is a force multiplier for a truly multiplatform world.
What are you waiting for?
Start building your cross-platform application in Golang today!
References
-
Go Official Documentation: The primary source for all information about the Go programming language.
-
Go Commands Documentation: Official documentation for Go's command-line tools, including
go build
. -
Go Modules Reference: The official reference for understanding and using Go's dependency management system.
-
gomobile
Repository and Wiki: The source code and official documentation for thegomobile
tool. -
GoReleaser Official Documentation: The complete documentation for the GoReleaser tool.
-
Fyne Developer Documentation: The official documentation and API reference for the Fyne GUI toolkit.
-
Wails Official Documentation: The official documentation for the Wails framework. https://wails.io/docs/gettingstarted/installation
-
Flutter Official Website: The official website for the Flutter framework, for comparison.
-
Kotlin Multiplatform Official Website: The official website for Kotlin Multiplatform, for comparison.
-
Cobra Library GitHub Repository: The source and documentation for the Cobra CLI library.
-
Viper Library GitHub Repository: The source and documentation for the Viper configuration library.
-
Android NDK Downloads: The official download page for the Android Native Development Kit required for
gomobile
. https://developer.android.com/ndk/downloads -
Apple's Command Line Tools (including
lipo
): Information on installing Xcode's command-line tools on macOS. https://developer.apple.com/library/archive/technotes/tn2339/_index.html
Google AI Studio was used in the outlining and research for this article.
You can find it here: https://aistudio.google.com
All images in this article are AI-generated by the author with NightCafe Studio.