The Chinese tech press has a new favorite headline: "Electron 慌了?Go 版 Electron 火了!打包体积直接缩小 10 倍" — roughly, "Electron panicking? The Go-powered Electron is on fire, and packages are 10× smaller."
It's clickbait. It's also… mostly true. The project in question is Wails (rhymes with Wales — the creator is Welsh, and the name started as a play on "Webview on Rails"). And the "10× smaller" claim deserves a closer look, because the real numbers are impressive even when they're not exactly 10×.
As a Go developer who has shipped more than a few desktop tools, let me tell you exactly what Wails is, where the size claims come from, and — the part most tutorials skip — how to take an existing SPA and package it as a real Android or iOS app with zero Go code changes.
Wails' core trick is simple: it does not embed a browser. Electron ships a full Chromium + Node.js runtime with every app — that's why a "hello world" Electron app weighs in around 150–200MB and idles at 100MB+ of RAM. Wails instead uses the native rendering engine already on the user's machine:
The Better Stack YouTube channel built the same screen-recorder app in all three frameworks and measured the shipping binaries:
| Framework | Bundle size | Warm start | Cold start |
|---|---|---|---|
| Wails | 52 MB | 395 ms | ~2,337 ms |
| Tauri | 57 MB | 410 ms | ~2,049 ms |
| Electron | 324 MB | 350 ms | ~1,890 ms |
So Wails is ~6.2× smaller than Electron for a feature-rich app, not 10×. Where does "10×" come from? The Wails v3 site quotes ~15MB binaries vs Electron's ~150MB for minimal apps — and that ratio genuinely lands near 10×. Like most marketing, it depends on what you're measuring. Either way, the direction is unmistakable: Electron ships a small planet with every app; Wails ships a single binary with your frontend baked in, served in-process with no localhost server and no open ports.

Wails is a framework for building desktop apps where:
// app.go — this is the whole "API surface" of a Wails app
func (a *App) Greet(name string) string {
return fmt.Sprintf("Hello %s, it's show time!", name)
}
// frontend — auto-generated binding, called like any async function
import { Greet } from "../wailsjs/go/main/App";
const msg = await Greet("Steve"); // "Hello Steve, it's show time!"
You also get native dialogs, native menus, dark/light mode, translucent "frosted glass" windows, a unified eventing system between Go and JS, and — in v3 — first-class multi-window support, a services model with static-analysis-generated bindings, and a transparent Taskfile-based build system you can actually read and customize.
Version reality check: Wails v2 is the stable release (go install github.com/wailsapp/wails/v2/cmd/wails@latest). Wails v3 is in beta (wails3), and while the desktop API is stable enough that teams run it in production, mobile support is explicitly experimental. For this article we use v3, because v3 is where the Android/iOS story lives.
The developer experience is the killer feature. In dev mode (wails dev), Wails hot-reloads your frontend, detects Go changes, rebuilds, and regenerates bindings — comment out a Go method and the TypeScript error appears in your editor instantly. Baseline memory sits around 10MB versus 100MB+ for Electron. Startup is under half a second.
The honest caveat: Go's ecosystem of native-API wrappers is thinner than Rust's. In the screen-recorder benchmark, the Tauri version pulled in a Rust crate and stayed in Rust; the Wails version required ~450 lines of hand-written Objective-C via CGo to access macOS CaptureKit. If you're a Go dev who loves Go, Wails is delightful — just budget for occasional CGo or platform-tag files when you need deep OS integration. If you'd rather stay in one language at all costs, Tauri's Rust crate ecosystem is the stronger bet. Pick your poison: Rust's learning curve or Go's occasionally thinner wrappers.

Here's the part everyone asks about. You have (or can scaffold) a Wails SPA. The same main.go and the same frontend build for desktop and Android — zero Go changes. Here's the full path, straight from the official docs.
go install github.com/wailsapp/wails/v3/cmd/wails3@latest
wails3 setup # guided toolchain check
wails3 init -n mymobileapp
cd mymobileapp
wails3 dev # confirm the desktop app works first
You need the Android SDK, NDK 26.3.x, and a JDK (OpenJDK 21):
sdkmanager "platform-tools" "platforms;android-35" "build-tools;35.0.0" \
"ndk;26.3.11579264" "emulator" \
"system-images;android-35;google_apis;arm64-v8a"
avdmanager create avd --name wails \
--package "system-images;android-35;google_apis;arm64-v8a" \
--device pixel_7
export ANDROID_HOME=~/android-sdk
Run wails3 doctor — it tells you exactly what's missing.
wails3 task android:run
One command that boots the emulator, generates bindings, builds your frontend, cross-compiles your Go to libwails.so via the NDK, assembles a debug APK with Gradle, installs it, and launches it. Your unmodified desktop SPA is now running on Android, with its assets served in-process through a WebViewAssetLoader — no localhost server, no ports. Debug WebViews are inspectable at chrome://inspect, and wails3 task android:logs streams logcat.
wails3 task android:package # production release APK
wails3 task android:bundle:fat # Play-ready AAB with arm64 + x86_64
Google Play requires the .aab format and target API 35+ (Android 15) for new submissions — the template already sets compileSdk/targetSdk to 35. Sign with your own keystore via env vars (ANDROID_KEYSTORE_FILE, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD) — with Play App Signing, your local keystore is just the upload key.
iOS builds require macOS with full Xcode (the command-line tools alone won't cut it), but the app story is identical: same main.go, same frontend, same @wailsio/runtime — "bring your app across as-is and ship," as the docs put it. The frontend renders in a WKWebView hosted by a UIKit UIViewController, with assets served via a custom wails:// scheme.
wails3 task ios:run # builds, boots a simulator, launches the app
wails3 task ios:logs:dev # stream simulator logs
wails3 task ios:xcode # open the generated Xcode project if needed
First run takes a few minutes (it compiles and caches the Wails framework for iOS); every run after is fast. Safari's Develop → Simulator gives you the full Web Inspector.
wails3 task ios:package \
IOS_PLATFORM=device \
CODESIGN_IDENTITY="Apple Development: You (TEAMID)" \
PROVISIONING_PROFILE=path/to/profile.mobileprovision
wails3 task ios:deploy-device # install to a physical iPhone
wails3 task ios:package:ipa IOS_PLATFORM=device ... # distribution .ipa
App identity lives in build/config.yml:
ios:
bundleID: com.example.myapp
displayName: My App
version: 1.0.0
minIOSVersion: "15.0"
Entitlements go in build/ios/entitlements.plist (device builds only). For managed signing, provisioning, and App Store archives, the docs recommend wails3 task ios:xcode and letting Xcode handle the certificate circus.
Two tiny patterns separate "it runs on my phone" from "it belongs on my phone."
1. Mobile-aware CSS — safe-area insets, no horizontal scroll, 44px tap targets:
body {
overflow-x: hidden;
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
}
button { min-height: 44px; min-width: 44px; }
2. Platform detection — hide desktop-only UI and gate native features:
const platform = (() => {
if (typeof window.wails?.platform === "function") return window.wails.platform(); // Android
if (window.webkit?.messageHandlers?.external) return "ios";
return "desktop";
})();
On the Go side, use build tags (//go:build ios, //go:build android) for platform-only code, application.System.IsMobile() for runtime branching, and the common:* event namespace (haptics, geolocation, biometrics, notifications, secure storage) for features both platforms share. The Kitchen Sink example (wails/v3/examples/mobile) demonstrates every one of these APIs across seven tabs — on iOS, Android, and desktop from one codebase.
Wails is the most compelling path today for Go developers who want one codebase across desktop and mobile without learning Rust or maintaining a separate React Native/Flutter project. The numbers hold up: ~6× smaller packages than Electron (approaching 10× for minimal apps), ~10MB baseline RAM, sub-second startups, and a genuinely pleasant DX with auto-generated type-safe bindings.
Caveats, stated plainly: mobile support is experimental in v3 (fine for tinkering and internal tools; budget for rough edges before a store launch), only the first window shows on mobile, and save-file dialogs are sandbox-only — the platform idioms differ from desktop. But the direction is clear: Wails v3 is where Go's desktop story gets its mobile sequel.
Want proof? Clone the repo, run wails3 task android:run, and watch your desktop SPA boot on a Pixel 7 emulator. Your Go code won't change. That's the headline worth writing.