Go, Browser—You Have To Talk! • The Applied Go Weekly Newsletter 2025-05-25
Your weekly source of Go news, tips, and projects
Go, Browser—You Have To Talk!
Hi ,
How do you add a web UI to your Go application? The classic approaches are:
- Write a rich client with heavy use of JavaScript, preferably using one of the available JS frameworks like React or VueJS
- Write a lean client and send every request to the server for processing on the backend
In today's Spotlight, I explore a third option: Bring Go to the browser. Invoking a func main
as a WebAssembly module is rather straightforward; the interesting question is how to make Go talk to the browser's DOM and interact with UI elements. It turns out that it's not that complicated either: With a few lines of code, you can watch updates of a text input field, process the contents, and write the result out into a <div>
.
How about writing a full in-browser app in Go, or writing a UI for your Go backend with just Go and HTML?
Happy coding!
–Christoph
Featured articles
Go Cryptography Security Audit - The Go Programming Language
The crypto libraries underwent an external security audit, and the results speak for the high quality of the libs: Only one minor finding in code that belongs to an inactive GOEXPERIMENT, and a few informational findings that are already addressed in the dev branch of Go 1.25.
Using Git as S3
GitHub is accessed through git
, right? Because, after all, it's based on git
, right?
Kris Tun thinks otherwise and wrote an S3 interface to GitHub.
Project of the week: Go Sandbox - An Advanced Online Go Playground
Now THAT's a playground I could get used to! (Not only because of the optional VIM keybindings...)
Podcast corner
Cup o' Go: Go gets audited, and Ian Lance Taylor talks about 19 years on the Go team
Ian Lance Taylor announced his departure from Google last week. Now he's the guest of this Cup o' Go episode and helps Shay figure out what's going on with Go.
Fallthrough: Blown Glass Half-Full of WebAssembly & SQLite
Would you deploy WebAssembly all over the world? Would you use SQLite to keep track of distributed data? And would you blow glass? Danielle Lancashire, a Principal Engineer at Fermyon, discusses these questions and more with Matt and Angelica.
Spotlight: WebAssembly in 5 minutes
The Go Wiki has the (maybe) most minimal code to demonstrate running Go in the browser with WebAssembly. It prints a message to the browser console.
But how can Go interact with the browser? Let's create a simple web app to explore reading from, and writing to, the browser's domain object model (DOM). Based on the code in the Go Wiki, we just need these additional ingredients:
- An
<input>
field to enter text and a<div>
as output target on the HTML page - Go code that reads the
<input>
field, converts the text to uppercase, and writes the result to the outputdiv
.
The final result will look like this:
I'll list all steps here so that they're easy to follow, even though this means duplicating some of the code from the Go Wiki.
0. Set up a new project
Create a directory of your choice, cd
into it, and initialize a new Go project:
go mod init <a module path of your choice>
1. Get the JavaScript support file
The Go code needs a JS support file for accessing the browser DOM. It must match the version of the Go toolchain, so ensure to fetch it from the current Go installation:
cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" .
2. Add input and output to the HTML page
Take the HTML file from the Go Wiki. It contains a script that loads the JS support file, and another script that loads and calls the WebAssembly module (WASM) that you'll build in step 4.
You only need to add the input field and the output div to the HTML body:
<!DOCTYPE html>
<html>
<!-- The head from the Go Wiki -->
<head>
<meta charset="utf-8" />
< script src="wasm_exec.js"></script>
< script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</head>
<!-- Add just this: -->
<body>
<input type="text" id="input" placeholder="Type here...">
<div id="output"></div>
</body>
</html>
Copy this HTML page into a file named "index.html".
3. Write Go code to read, convert, and write the input
In this step, you'll create Go code that:
- Defines a function that acts as an event listener for the input field
- Makes this function read from the input field, convert the field value to uppercase, and write the result to the output div
- Registers this function as an event handler to the input field
For easy copying and pasting, I do not split the code into many small snippets and comment on each; rather, find relevant comments inside the code that will explain what's going on (and no, I don't intend to promote the bad practice of commenting what code does. These comments are for learning purposes and mostly shouldn't exist in non-educational code):
package main
import (
"strings"
"syscall/js"
)
// This function returns a js.Func that acts as an event listener for the input field. It receives the input field via the "this" parameter.
func uppercaseFunction() js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) any {
// Get the input field's value
inputText := this.Get("value").String()
// Process the value
uppercaseText := strings.ToUpper(inputText)
// Get the DOM document object
document := js.Global().Get("document")
// Find the output element and write the uppercase text to it
outputElement := document.Call("getElementById", "output")
outputElement.Set("textContent", uppercaseText)
return nil
})
}
func main() {
// Add the uppercase function as an event listener to the input field
// This line saves you from having to write JavaScript for adding the event handler
js.Global().Get("document").Call("getElementById", "input").Call("addEventListener", "input", uppercaseFunction())
// Keep the WebAssembly program running indefinitely
// Without this, the program would exit and JavaScript couldn't call our function
select {}
}
Create a new file main.go
and copy the above code into it.
4. Compile the Go code to a WebAssembly module
Inside the HTML document, the initialization script wants to fetch a WebAssembly module named main.wasm
, which does not exist yet.
Create this file from the Go code as follows:
GOOS=js GOARCH=wasm go build -o main.wasm
The OS and ARCH targets tell Go to build a WASM for use in the browser (with JavaScript). The -o
flag ensures the compiled WASM has the name the initialization script expects.
For more examples on interacting with the DOM, see the section Interacting with the DOM in the Go Wiki.
5. Run a web server to serve
At this point, your project directory should contain these files:
index.html
main.go
main.wasm
wasm_exec.js
go.mod
Run a Web server of your choice to serve "index.html". If you have Caddy installed, this step is straightforward:
caddy file-server -l localhost:8080
Another option is Python:
python3 -m http.server 8080
Then, open the page at localhost:8080 and type something into the input field.
Does it work? Wonderful! Take this as a starting point for some great WebAssembly project!
More articles, videos, talks
Exploring the Rate package and the Token Bucket algorithm - mfbmina.dev
Matheus Mina tests another way of traffic shaping.
Interacting With the Docker Engine in Go | Alexis Bouchez's personal website
Docker is great for deploying Go apps, but what if you want to control Docker from your app? Alexis Bouchez rebuilds common Docker commands in Go.
too much go misdirection
If you find yourself writing unsafe
code requiring knowledge of stdlib internals ... go for a walk in the park.
Every project needs a website, a blog, and maybe also a newsletter. Markdown Ninja provides all of these. Still in early stages, but promising.
Building a Minesweeper game with Go and Raylib - YouTube
Watch Alex Pliutau write Minesweeper with Raylib, a C-based videogame programming library with no external dependencies.
Projects
Libraries
GitHub - VincentBrodin/suddig: A fast fuzzy finding library writen in go
Find things even if you don't know the exact spelling, without having to resort to LLMs.
GitHub - drpaneas/pigo8
Build retro console games with Go and Ebitengine but with the developer experience of PICO-8.
GitHub - stoolap/stoolap: Stoolap is a high-performance, SQL database written in pure Go with zero dependencies.
A hybrid transactional and analytical, columnar SQL database that emerged from a research project and has an ... interesting name. (According to the author, it's a combination of "storage"and "olap".
Tools and applications
GitHub - matthieugusmini/rift: Stay up to date with League of Legends eSport in your terminal!
Track leagues, players, matches, and results of League of Legends in your terminal.
FFmate documentation
Build video processing workflows with ffmpeg
and FFmate!
Topeka - MCP Server Generation
Turn your gRPC service into an MCP server, to make it accessible as a tool for large language models. NOTE: Don't confuse this project with Redpanda's project of the same name.
Gostman | terminal-based API client. | Gostman
If you need something like Postman or Bruno but prefer the terminal, try gostman
.
Completely unrelated to Go
Finding hard 24 puzzles with planner programming
"The 24 puzzle is an arithmetical puzzle in which the objective is to find a way to manipulate four integers so that the end result is 24. For example, for the numbers 4, 7, 8, 8
, a possible solution is (7−(8÷8))×4=24
. Note that all four numbers must be used exactly once." (Wikipedia)
How to solve such puzzles? With planner programming, of course! Says Hillel Wayne and demonstrates the same using the language Picat, which has a built-in planner module.
No Silver Bullet: Sync vs Async Architecture
Miłosz and Robert discuss how a seemingly straightforward architectural decision can influence your app's user experience and your on-call sleep schedule.

Happy coding! ʕ◔ϖ◔ʔ
Questions or feedback? Drop me a line. I'd love to hear from you.
Best from Munich, Christoph
Not a subscriber yet?
If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding.
Find the subscription form at the end of this page.
How I can help
If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):
On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.
Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff.
My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.
Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.
Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany