Build System
Unified Build System
Section titled “Unified Build System”Wails provides a unified build system that compiles Go code, bundles frontend assets, embeds everything into a single executable, and handles platform-specific builds—all with one command.
wails3 buildOutput: Native executable with everything embedded.
Build Process Overview
Section titled “Build Process Overview”[Build Process Diagram Placeholder]
Build Phases
Section titled “Build Phases”1. Analysis Phase
Section titled “1. Analysis Phase”Wails scans your Go code to understand your services:
type GreetService struct { prefix string}
func (g *GreetService) Greet(name string) string { return g.prefix + name + "!"}What Wails extracts:
- Service name:
GreetService - Method name:
Greet - Parameter types:
string - Return types:
string
Used for: Generating TypeScript bindings
2. Generation Phase
Section titled “2. Generation Phase”TypeScript Bindings
Section titled “TypeScript Bindings”Wails generates type-safe bindings:
export function Greet(name: string): Promise<string> { return window.wails.Call('GreetService.Greet', name)}Benefits:
- Full type safety
- IDE autocomplete
- Compile-time errors
- JSDoc comments
Frontend Build
Section titled “Frontend Build”Your frontend bundler runs (Vite, webpack, etc.):
# Vite examplevite build --outDir distWhat happens:
- JavaScript/TypeScript compiled
- CSS processed and minified
- Assets optimised
- Source maps generated (dev only)
- Output to
frontend/dist/
3. Compilation Phase
Section titled “3. Compilation Phase”Go Compilation
Section titled “Go Compilation”Go code is compiled with optimisations:
go build -ldflags="-s -w" -o myapp.exeFlags:
-s: Strip symbol table-w: Strip DWARF debugging info- Result: Smaller binary (~30% reduction)
Platform-specific:
- Windows:
.exewith icon embedded - macOS:
.appbundle structure - Linux: ELF binary
Asset Embedding
Section titled “Asset Embedding”Frontend assets are embedded into the Go binary:
//go:embed frontend/distvar assets embed.FSResult: Single executable with everything inside.
4. Output
Section titled “4. Output”Single native binary:
- Windows:
myapp.exe(~15MB) - macOS:
myapp.app(~15MB) - Linux:
myapp(~15MB)
No dependencies (except system WebView).
Development vs Production
Section titled “Development vs Production”Optimised for speed:
wails3 devWhat happens:
- Starts frontend dev server (Vite on port 5173)
- Compiles Go without optimisations
- Launches app pointing to dev server
- Enables hot reload
- Includes source maps
Characteristics:
- Fast rebuilds (<1s for frontend changes)
- No asset embedding (served from dev server)
- Debug symbols included
- Source maps enabled
- Verbose logging
File size: Larger (~50MB with debug symbols)
Optimised for size and performance:
wails3 buildWhat happens:
- Builds frontend for production (minified)
- Compiles Go with optimisations
- Strips debug symbols
- Embeds assets
- Creates single binary
Characteristics:
- Optimised code (minified, tree-shaken)
- Assets embedded (no external files)
- Debug symbols stripped
- No source maps
- Minimal logging
File size: Smaller (~15MB)
Build Commands
Section titled “Build Commands”Basic Build
Section titled “Basic Build”wails3 buildOutput: build/bin/myapp[.exe]
Build for Specific Platform
Section titled “Build for Specific Platform”# Build for Windows (from any OS)wails3 build -platform windows/amd64
# Build for macOSwails3 build -platform darwin/amd64wails3 build -platform darwin/arm64
# Build for Linuxwails3 build -platform linux/amd64Cross-compilation: Build for any platform from any platform.
Build with Options
Section titled “Build with Options”# Custom output directorywails3 build -o ./dist/myapp
# Skip frontend build (use existing)wails3 build -skipbindings
# Clean build (remove cache)wails3 build -clean
# Verbose outputwails3 build -vBuild Modes
Section titled “Build Modes”# Debug build (includes symbols)wails3 build -debug
# Production build (default, optimised)wails3 build
# Development build (fast, unoptimised)wails3 build -devbuildBuild Configuration
Section titled “Build Configuration”Taskfile.yml
Section titled “Taskfile.yml”Wails uses Taskfile for build configuration:
version: '3'
tasks: build: desc: Build the application cmds: - wails3 build
build:windows: desc: Build for Windows cmds: - wails3 build -platform windows/amd64
build:macos: desc: Build for macOS (Universal) cmds: - wails3 build -platform darwin/amd64 - wails3 build -platform darwin/arm64 - lipo -create -output build/bin/myapp.app build/bin/myapp-amd64.app build/bin/myapp-arm64.app
build:linux: desc: Build for Linux cmds: - wails3 build -platform linux/amd64Run tasks:
task build:windowstask build:macostask build:linuxBuild Options File
Section titled “Build Options File”Create build/build.json for persistent configuration:
{ "name": "My Application", "version": "1.0.0", "author": "Your Name", "description": "Application description", "icon": "build/appicon.png", "outputFilename": "myapp", "platforms": ["windows/amd64", "darwin/amd64", "linux/amd64"], "frontend": { "dir": "./frontend", "install": "npm install", "build": "npm run build", "dev": "npm run dev" }, "go": { "ldflags": "-s -w -X main.version={{.Version}}" }}Asset Embedding
Section titled “Asset Embedding”How It Works
Section titled “How It Works”Wails uses Go’s embed package:
package main
import ( "embed" "github.com/wailsapp/wails/v3/pkg/application")
//go:embed frontend/distvar assets embed.FS
func main() { app := application.New(application.Options{ Name: "My App", Assets: application.AssetOptions{ Handler: application.AssetFileServerFS(assets), }, })
app.Window.New() app.Run()}At build time:
- Frontend built to
frontend/dist/ //go:embeddirective includes files- Files compiled into binary
- Binary contains everything
At runtime:
- App starts
- Assets served from memory
- No disk I/O for assets
- Fast loading
Custom Assets
Section titled “Custom Assets”Embed additional files:
//go:embed frontend/distvar frontendAssets embed.FS
//go:embed data/*.jsonvar dataAssets embed.FS
//go:embed templates/*.htmlvar templateAssets embed.FSBuild Optimisations
Section titled “Build Optimisations”Frontend Optimisations
Section titled “Frontend Optimisations”Vite (default):
export default { build: { minify: 'terser', terserOptions: { compress: { drop_console: true, // Remove console.log drop_debugger: true, }, }, rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], // Separate vendor bundle }, }, }, },}Results:
- JavaScript minified (~70% reduction)
- CSS minified (~60% reduction)
- Images optimised
- Tree-shaking applied
Go Optimisations
Section titled “Go Optimisations”Compiler flags:
-ldflags="-s -w"-s: Strip symbol table (~10% reduction)-w: Strip DWARF debug info (~20% reduction)
Additional optimisations:
-ldflags="-s -w -X main.version=1.0.0"-X: Set variable values at build time- Useful for version numbers, build dates
Binary Compression
Section titled “Binary Compression”UPX (optional):
# After buildingupx --best build/bin/myapp.exeResults:
- ~50% size reduction
- Slightly slower startup (~100ms)
- Not recommended for macOS (code signing issues)
Platform-Specific Builds
Section titled “Platform-Specific Builds”Windows
Section titled “Windows”Output: myapp.exe
Includes:
- Application icon
- Version information
- Manifest (UAC settings)
Icon:
# Specify iconwails3 build -icon build/appicon.pngWails converts PNG to .ico automatically.
Manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" name="MyApp"/> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo></assembly>Output: myapp.app (application bundle)
Structure:
myapp.app/├── Contents/│ ├── Info.plist # App metadata│ ├── MacOS/│ │ └── myapp # Binary│ ├── Resources/│ │ └── icon.icns # Icon│ └── _CodeSignature/ # Code signature (if signed)Info.plist:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>CFBundleName</key> <string>My App</string> <key>CFBundleIdentifier</key> <string>com.example.myapp</string> <key>CFBundleVersion</key> <string>1.0.0</string></dict></plist>Universal Binary:
# Build for both architectureswails3 build -platform darwin/amd64wails3 build -platform darwin/arm64
# Combine into universal binarylipo -create -output myapp-universal \ build/bin/myapp-amd64 \ build/bin/myapp-arm64Output: myapp (ELF binary)
Dependencies:
- GTK3
- WebKitGTK
Desktop file:
# myapp.desktop[Desktop Entry]Name=My AppExec=/usr/bin/myappIcon=myappType=ApplicationCategories=Utility;Installation:
# Copy binarysudo cp myapp /usr/bin/
# Copy desktop filesudo cp myapp.desktop /usr/share/applications/
# Copy iconsudo cp icon.png /usr/share/icons/hicolor/256x256/apps/myapp.pngBuild Performance
Section titled “Build Performance”Typical Build Times
Section titled “Typical Build Times”| Phase | Time | Notes |
|---|---|---|
| Analysis | <1s | Go code scanning |
| Binding Generation | <1s | TypeScript generation |
| Frontend Build | 5-30s | Depends on project size |
| Go Compilation | 2-10s | Depends on code size |
| Asset Embedding | <1s | Embedding frontend |
| Total | 10-45s | First build |
| Incremental | 5-15s | Subsequent builds |
Speeding Up Builds
Section titled “Speeding Up Builds”1. Use build cache:
# Go build cache is automatic# Frontend cache (Vite)npm run build # Uses cache by default2. Skip unchanged steps:
# Skip frontend if unchangedwails3 build -skipbindings3. Parallel builds:
# Build multiple platforms in parallelwails3 build -platform windows/amd64 &wails3 build -platform darwin/amd64 &wails3 build -platform linux/amd64 &wait4. Use faster tools:
# Use esbuild instead of webpack# (Vite uses esbuild by default)Troubleshooting
Section titled “Troubleshooting”Build Fails
Section titled “Build Fails”Symptom: wails3 build exits with error
Common causes:
-
Go compilation error
Terminal window # Check Go code compilesgo build -
Frontend build error
Terminal window # Check frontend buildscd frontendnpm run build -
Missing dependencies
Terminal window # Install dependenciesnpm installgo mod download
Binary Too Large
Section titled “Binary Too Large”Symptom: Binary is >50MB
Solutions:
-
Strip debug symbols (should be automatic)
Terminal window wails3 build # Already includes -ldflags="-s -w" -
Check embedded assets
Terminal window # Remove unnecessary files from frontend/dist/# Check for large images, videos, etc. -
Use UPX compression
Terminal window upx --best build/bin/myapp.exe
Slow Builds
Section titled “Slow Builds”Symptom: Builds take >1 minute
Solutions:
-
Use build cache
- Go cache is automatic
- Frontend cache (Vite) is automatic
-
Skip unchanged steps
Terminal window wails3 build -skipbindings -
Optimise frontend build
vite.config.js export default {build: {minify: 'esbuild', // Faster than terser},}
Best Practices
Section titled “Best Practices”- Use
wails3 devduring development - Fast iteration - Use
wails3 buildfor releases - Optimised output - Version your builds - Use
-ldflagsto embed version - Test builds on target platforms - Cross-compilation isn’t perfect
- Keep frontend builds fast - Optimise bundler config
- Use build cache - Speeds up subsequent builds
❌ Don’t
Section titled “❌ Don’t”- Don’t commit
build/directory - Add to.gitignore - Don’t skip testing builds - Always test before release
- Don’t embed unnecessary assets - Keep binaries small
- Don’t use debug builds for production - Use optimised builds
- Don’t forget code signing - Required for distribution
Next Steps
Section titled “Next Steps”Building Applications - Detailed guide to building and packaging
Learn More →
Cross-Platform Builds - Build for all platforms from one machine
Learn More →
Creating Installers - Create installers for end users
Learn More →
Questions about building? Ask in Discord or check the build examples.