I have been working on Glaze, a small desktop WebView toolkit for Go.
The short version: Glaze lets a Go program open a native desktop window backed by the WebView already available on the operating system, without using CGo.
It currently targets:
- macOS, through WKWebView
- Linux, through WebKitGTK
- Windows, through WebView2
The project is still young, but the core idea is already useful: keep small Go desktop tools close to the normal Go workflow.
No C compiler in the build path.
No bundled native helper library.
No large application framework around it.
Just Go code calling the system WebView.
Why I wanted this
I write a lot of small tools in Go.
Some of them are fine as CLI programs. Others need a basic interface: a form, a preview, a local dashboard, a small editor, or a way to inspect and manipulate data visually.
For those cases, HTML is often enough. The browser gives me layout, text rendering, forms, tables, keyboard handling, and a familiar debugging model.
But I do not always want to ship a web server as the user interface. I also do not always want to pull in a large desktop framework when all I need is a native window around a local UI.
A WebView is a reasonable middle ground.
The problem is that many WebView solutions eventually bring CGo, native build tooling, helper libraries, or larger framework assumptions into the project.
That is not necessarily wrong. For many applications, those trade-offs are acceptable.
For this project, I wanted something narrower.
The design constraint
The main constraint behind Glaze is simple:
Use the WebView already provided by the OS, but call it from Go without CGo.
Glaze uses purego to call native platform APIs directly from Go.
That means each backend talks to the platform WebView:
- WKWebView on macOS
- WebKitGTK on Linux
- WebView2 on Windows
The result is not a full GUI toolkit. That is intentional.
Glaze is focused on the window, the WebView, JavaScript-to-Go bindings, and a few desktop helpers that are useful for small tools.
Hello world
A minimal Glaze program looks like this:
package main
import (
"log"
"github.com/crgimenes/glaze"
)
func main() {
w, err := glaze.New(true)
if err != nil {
log.Fatal(err)
}
defer w.Destroy()
w.SetTitle("Glaze")
w.SetSize(800, 600, glaze.HintNone)
w.SetHtml("<h1>Hello from Glaze</h1>")
w.Run()
}
That opens a native window and renders HTML inside the system WebView.
A local Go app in a desktop window
One of the patterns I care about most is turning an existing net/http application into a desktop app with minimal changes.
Glaze has an AppWindow helper for that.
package main
import (
"fmt"
"log"
"net/http"
"github.com/crgimenes/glaze"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, err := fmt.Fprint(w, `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Glaze App</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 2rem;
}
button {
font: inherit;
padding: 0.5rem 1rem;
}
</style>
</head>
<body>
<h1>Local Go UI</h1>
<p>This page is served by a Go http.Handler and displayed in a desktop WebView.</p>
<button onclick="location.reload()">Reload</button>
</body>
</html>`)
if err != nil {
log.Printf("write response: %v", err)
}
})
err := glaze.AppWindow(glaze.AppOptions{
Title: "Glaze App",
Width: 1024,
Height: 700,
Handler: mux,
})
if err != nil {
log.Fatal(err)
}
}
This is the style of application I had in mind: local tools, internal utilities, small editors, dashboards, inspectors, and experiments.
The UI can still be plain HTML, CSS, and JavaScript. The backend can still be normal Go.
Calling Go from JavaScript
Glaze also supports binding Go functions to JavaScript.
That makes it possible to keep the UI lightweight while still doing real work in Go.
The goal is not to turn every application into a complex frontend. The useful case is exposing a small surface area: save a file, query local state, run a calculation, trigger an operation, or send an event.
This fits well with small tools where most of the logic belongs in Go and the WebView is mainly the presentation layer.
What Glaze is not trying to be
Glaze is not trying to replace mature GUI toolkits.
It is also not trying to replace larger frameworks for building full desktop applications.
Those projects usually solve broader problems: packaging, application lifecycle, icons, installers, auto-update, system integration, custom controls, and more.
Glaze is intentionally smaller.
The target use case is closer to:
- “I have a Go tool and want a small local UI”
- “I already have an HTTP handler and want to show it in a desktop window”
- “I want HTML for layout but do not want to ship a browser”
- “I want to avoid CGo in this project”
- “I want a thin WebView layer instead of a full application framework”
That scope keeps the API easier to reason about.
Platform notes
macOS is the cleanest case because the Cocoa and WebKit frameworks are already part of the system.
Windows depends on the Microsoft Edge WebView2 Runtime, which is already present on current Windows installations in many cases.
Linux is the hard case. Different distributions package WebKitGTK differently, and dynamic library names matter. Glaze tries to detect GTK4/WebKitGTK first and falls back to GTK3/WebKitGTK where appropriate, but Linux still needs more testing across distributions.
That is one of the areas where feedback would be useful.
Current features
At the moment Glaze includes:
- desktop WebView windows
- JavaScript-to-Go binding
-
BindMethodshelper for exposing exported Go methods -
RenderHTMLhelper for Go templates -
AppWindowfor localnet/httpapps - Go-to-JavaScript event bridge
- native file dialogs
- native menu support on macOS and Windows
- runnable visual examples
The repository also includes small demos such as Game of Life, Starfield, Doom Fire, Mandelbrot, Falling Sand, Raycasting, and a Filo REPL.
Glaze
Glaze is a desktop WebView binding for Go. It is a pure-Go port of webview/webview built on purego, keeping CGo out of the picture. Each backend talks to the WebView framework the OS already ships -- WKWebView on macOS, WebKitGTK on Linux, WebView2 on Windows -- so nothing native is bundled.
It started as a fork of go-webview but has diverged enough to live as a separate codebase with its own goals and API.
Examples
Why no CGo
This is the whole point of the project, and it's the part that's easy to miss. Most native-WebView bindings reach for CGo, which quietly takes back the things that make Go pleasant to ship: cross-compiling suddenly needs a matching C cross-compiler for every target (mingw for Windows, a sysroot for Linux), builds stop being reproducible, and go…
Trade-offs
The main benefit is keeping the project close to regular Go development.
The main cost is that Glaze sits close to native platform APIs, so platform differences are real.
Some trade-offs are deliberate:
- It does not bundle a browser.
- It does not try to hide every OS difference.
- It does not try to become a complete desktop framework.
- Linux support depends on system WebKitGTK libraries.
- Windows support depends on WebView2 runtime behavior.
For my use case, that is acceptable. I prefer a small, explicit layer over a large abstraction that hides too much.
Where I want to take it
The immediate focus is stability and examples.
The most valuable improvements right now are:
- testing on more Linux distributions
- better diagnostics when system WebView libraries are missing
- more examples showing realistic local tools
- API feedback from Go developers who build small desktop utilities
- clearer documentation for platform-specific behavior
I am also interested in keeping the project boring in the good sense: small API, predictable behavior, explicit errors, and no unnecessary magic.
Repository
The project is here:
https://github.com/crgimenes/glaze
Feedback is welcome, especially around the API shape, Linux/WebKitGTK behavior, and whether the examples make the intended use case clear.








Top comments (1)
Avoiding CGo changes the whole deployment story. It would be interesting to see how this handles platform differences and native WebView features.