One Go Codebase, Five Platforms: My Cross-Platform Build Journey

Written by thomascherickal | Published 2025/08/07
Tech Story Tags: golang | cross-platform-app-development | cross-platform-mobile | cross-platform-desktop | environment-variables | comparison-with-flutter | comparison-with-kotlin | one-go-codebase

TLDRGo is a programming language that allows developers to write code for multiple operating systems. This article shows you all the details you need to know.via the TL;DR App

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, and ios.
  • 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), and arm.

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 and hugo, 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 like dpkg or rpmbuild 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

  1. Go Official Documentation: The primary source for all information about the Go programming language.

    https://go.dev/doc/

  2. Go Commands Documentation: Official documentation for Go's command-line tools, including go build.

    https://go.dev/doc/cmd

  3. Go Modules Reference: The official reference for understanding and using Go's dependency management system.

    https://go.dev/ref/mod

  4. gomobile Repository and Wiki: The source code and official documentation for the gomobile tool.

    https://github.com/golang/mobile

  5. GoReleaser Official Documentation: The complete documentation for the GoReleaser tool.

    https://goreleaser.com/

  6. Fyne Developer Documentation: The official documentation and API reference for the Fyne GUI toolkit.

    https://developer.fyne.io/

  7. Wails Official Documentation: The official documentation for the Wails framework. https://wails.io/docs/gettingstarted/installation

  8. Flutter Official Website: The official website for the Flutter framework, for comparison.

    https://flutter.dev/

  9. Kotlin Multiplatform Official Website: The official website for Kotlin Multiplatform, for comparison.

    https://kotlinlang.org/docs/multiplatform-get-started.html

  10. Cobra Library GitHub Repository: The source and documentation for the Cobra CLI library.

    https://github.com/spf13/cobra

  11. Viper Library GitHub Repository: The source and documentation for the Viper configuration library.

    https://github.com/spf13/viper

  12. Android NDK Downloads: The official download page for the Android Native Development Kit required for gomobile. https://developer.android.com/ndk/downloads

  13. 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.


Written by thomascherickal | The Digital Futurist. The | Gen AI | Agents | Blockchain | Quantum | Mastery Playbook. Subscribe!
Published by HackerNoon on 2025/08/07