Contribute

Edit this documentation

Translate the documentation or open the complete project on your computer.

Nothing is published until you choose to submit your work.

How Wails Works

Understanding the Wails architecture and how it achieves native performance

Wails is a framework for building desktop applications using Go for the backend and web technologies for the frontend. But unlike Electron, Wails doesn’t bundle a browser—it uses the operating system’s native WebView.

Wails App, Frontend, Go Backend, Operating System, Initialisation, Serves Static Web App, Render Site via OS-native WebView, Regular Communication, Make API-style call, Service processes request, Generate Response, Process response

Key differences from Electron:

Aspect Wails Electron
Browser OS-provided WebView Bundled Chromium (~100MB)
Backend Go (compiled) Node.js (interpreted)
Communication In-memory bridge IPC (inter-process)
Bundle Size ~15MB ~150MB
Memory ~10MB ~100MB+
Startup <0.5s 2-3s

Core Components

1. Native WebView

Wails uses the operating system’s built-in web rendering engine:

WebView2 (Microsoft Edge WebView2)

  • Based on Chromium (same as Edge browser)
  • Pre-installed on Windows 10/11
  • Automatic updates via Windows Update
  • Full modern web standards support

Why this matters:

  • No bundled browser → Smaller app size
  • OS-native → Better integration and performance
  • Auto-updates → Security patches from OS updates
  • Familiar rendering → Same as system browser

2. The Wails Bridge

The bridge is the heart of Wails—it enables direct communication between Go and JavaScript.

Frontend (JavaScript), Wails Bridge, JSON Encoder, Method Router, JSON Decoder, Backend (Go), Registered Services

How it works:

  1. Frontend calls a Go method (via auto-generated binding)
  2. Bridge encodes the call to JSON (method name + arguments)
  3. Router finds the Go method in registered services
  4. Go method executes and returns a value
  5. Bridge decodes the result and sends back to frontend
  6. Promise resolves in JavaScript with the result

Performance characteristics:

  • In-memory: No network overhead, no HTTP
  • Zero-copy where possible (for large data)
  • Async by default: Non-blocking on both sides
  • Type-safe: TypeScript definitions auto-generated

3. Service System

Services are the recommended way to expose Go functionality to the frontend.

go
// Define a service (just a regular Go struct)
type GreetService struct {
    prefix string
}

// Methods with exported names are automatically available
func (g *GreetService) Greet(name string) string {
    return g.prefix + name + "!"
}

func (g *GreetService) GetTime() time.Time {
    return time.Now()
}

// Register the service
app := application.New(application.Options{
    Services: []application.Service{
        application.NewService(&GreetService{prefix: "Hello, "}),
    },
})

Service discovery:

  • Wails scans your struct at startup
  • Exported methods become callable from frontend
  • Type information is extracted for TypeScript bindings
  • Error handling is automatic (Go errors → JS exceptions)

Generated TypeScript binding:

typescript
// Auto-generated in frontend/bindings/GreetService.ts
export function Greet(name: string): Promise<string>
export function GetTime(): Promise<Date>

Why services?

  • Type-safe: Full TypeScript support
  • Auto-discovery: No manual registration of methods
  • Organised: Group related functionality
  • Testable: Services are just Go structs

Learn more about services →

4. Event System

Events enable pub/sub communication between components.

Wails Event System, Window 1, Window 2, Go Backend, Event Driver, Subscribe to 'data-updated' events, Subscribe to 'data-updated' events, App Emit('data-updated', data), Subscriber processes On('data-updated', handler), Subscriber processes On('data-updated', handler)

Use cases:

  • Window communication: One window notifies others
  • Background tasks: Go service notifies UI of progress
  • State synchronisation: Keep multiple windows in sync
  • Loose coupling: Components don’t need direct references

Example:

go
// Go: Emit an event
app.Event.Emit("user-logged-in", user)
javascript
// JavaScript: Listen for event
import { Events } from '@wailsio/runtime'

Events.On('user-logged-in', (user) => {
    console.log('User logged in:', user)
})

Learn more about events →

Application Lifecycle

Understanding the lifecycle helps you know when to initialise resources and clean up.

Application Start, Initialisation, Create Application, Register Services, Setup Windows/Menus, Event Loop, Process Events, Handle Messages, Update UI, Shutdown, Cleanup Resources, Save State, Application End

Lifecycle hooks:

go
app := application.New(application.Options{
    Name: "My App",

    // Cleanly intercept quit requests (e.g. unsaved changes).
    ShouldQuit: func() bool { return true },

    // Called when the app is confirmed to be quitting — save state, close connections, etc.
    OnShutdown: func() {},
})

There is no OnStartup field on application.Options. Startup work belongs in a service’s ServiceStartup(ctx, options), in a callback registered via app.Event.OnApplicationEvent(events.Common.ApplicationStarted, ...), or simply before app.Run().

Learn more about lifecycle →

Build Process

Understanding how Wails builds your application:

Source Code, Go Code (main.go, services), Frontend Code (HTML/CSS/JS), Build Process, Analyse Go Code, Generate Bindings, Build Frontend, Compile Go, Embed Assets, Output, Native Binary (myapp.exe/.app)

Build steps:

  1. Analyse Go code
  • Scan services for exported methods
  • Extract parameter and return types
  • Generate method signatures
  1. Generate TypeScript bindings
  • Create .ts files for each service
  • Include full type definitions
  • Add JSDoc comments
  1. Build frontend
  • Run your bundler (Vite, webpack, etc.)
  • Minify and optimise
  • Output to frontend/dist/
  1. Compile Go
  • Compile with optimisations (-ldflags="-s -w")
  • Include build metadata
  • Platform-specific compilation
  1. Embed assets
  • Embed frontend files into Go binary
  • Compress assets
  • Create single executable

Result: A single native executable with everything embedded.

Learn more about building →

Development vs Production

Wails behaves differently in development and production:

Characteristics:

  • Hot reload: Frontend changes reload instantly
  • Source maps: Debug with original source
  • DevTools: Browser DevTools available
  • Logging: Verbose logging enabled
  • External frontend: Served from dev server (Vite)

How it works:

Wails App, Vite Dev Server (localhost:5173), WebView

Benefits:

  • Instant feedback on changes
  • Full debugging capabilities
  • Faster iteration

Memory Model

Understanding memory usage helps you build efficient applications.

Memory regions:

  1. Go Heap
  • Your services and application state
  • Managed by Go garbage collector
  • Typically 5-10MB for simple apps
  1. WebView Memory
  • DOM, JavaScript heap, CSS
  • Managed by WebView’s engine
  • Typically 10-20MB for simple apps
  1. Bridge Memory
  • Message buffers for communication
  • Minimal overhead (<1MB)
  • Zero-copy for large data where possible

Optimisation tips:

  • Avoid large data transfers: Pass IDs, fetch details on demand
  • Use events for updates: Don’t poll from frontend
  • Stream large files: Don’t load entirely into memory
  • Clean up listeners: Remove event listeners when done

Learn more about performance →

Security Model

Wails provides a secure-by-default architecture:

Frontend (Untrusted), Wails Bridge (Validation), Backend (Trusted)

Security features:

  1. Method whitelisting
  • Only exported methods are callable
  • Private methods are inaccessible
  • Explicit service registration required
  1. Type validation
  • Arguments checked against Go types
  • Invalid types rejected
  • Prevents injection attacks
  1. No eval()
  • Frontend can’t execute arbitrary Go code
  • Only predefined methods callable
  • No dynamic code execution
  1. Context isolation
  • Each window has its own context
  • Services can check caller context
  • Permissions per window possible

Best practices:

  • Validate user input in Go (don’t trust frontend)
  • Use context for authentication/authorisation
  • Sanitise file paths before file operations
  • Rate limit expensive operations

Learn more about security →

Next Steps

Application Lifecycle - Understand startup, shutdown, and lifecycle hooks Learn More →

Go-Frontend Bridge - Deep dive into how the bridge works Learn More →

Build System - Understand how Wails builds your application Learn More →

Start Building - Apply what you’ve learned in a tutorial Tutorials →


Questions about architecture? Ask in Discord or check the API reference.

Edit page

Last updated: