Wails lets you build desktop applications using Go for the backend and any web framework for the frontend. Native feel, Go performance, modern web UI — without Electron's bloat.
Why Wails?
- Go backend — goroutines, channels, the entire Go ecosystem
- Any frontend — React, Vue, Svelte, Solid, plain HTML
- Native webview — not Chromium (unlike Electron), ~5MB binary
- Bidirectional binding — call Go from JS, call JS from Go
Quick Start
go install github.com/wailsapp/wails/v2/cmd/wails@latest
wails init -n myapp -t react-ts
cd myapp
wails dev
Go Backend
// app.go
package main
import "context"
type App struct {
ctx context.Context
}
func NewApp() *App {
return &App{}
}
func (a *App) startup(ctx context.Context) {
a.ctx = ctx
}
// Exposed to frontend automatically
func (a *App) Greet(name string) string {
return fmt.Sprintf("Hello %s, from Go!", name)
}
func (a *App) GetUsers() ([]User, error) {
return db.GetAllUsers()
}
func (a *App) SaveFile(content string) error {
return os.WriteFile("output.txt", []byte(content), 0644)
}
Frontend (React)
import { Greet, GetUsers, SaveFile } from '../wailsjs/go/main/App';
function App() {
const [greeting, setGreeting] = useState('');
const handleGreet = async () => {
const result = await Greet('Alice');
setGreeting(result); // "Hello Alice, from Go!"
};
const handleUsers = async () => {
const users = await GetUsers(); // Typed from Go struct!
console.log(users);
};
return (
<div>
<button onClick={handleGreet}>Greet</button>
<p>{greeting}</p>
</div>
);
}
Events System
// Go → Frontend
func (a *App) StartProcess() {
for i := 0; i <= 100; i++ {
runtime.EventsEmit(a.ctx, "progress", i)
time.Sleep(50 * time.Millisecond)
}
}
// Frontend
import { EventsOn } from '../wailsjs/runtime';
EventsOn('progress', (value: number) => {
setProgress(value);
});
Dialogs
func (a *App) OpenFile() string {
file, _ := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "Select a file",
Filters: []runtime.FileFilter{
{DisplayName: "Text Files", Pattern: "*.txt;*.md"},
},
})
return file
}
func (a *App) SaveDialog() string {
file, _ := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
Title: "Save as",
})
return file
}
Build
# Development
wails dev
# Production build
wails build
# Cross-compile
wails build -platform windows/amd64
wails build -platform darwin/universal
wails build -platform linux/amd64
Building Go desktop tools? Check out my Apify actors for data extraction APIs, or email spinov001@gmail.com for custom Go desktop apps.
Wails, Tauri, or Electron — what do you build desktop apps with? Share below!
Top comments (0)