Build powerful, reactive, and type-safe web frontends with pure Go.
Golem is an experimental web framework that leverages WebAssembly to allow developers to write frontend applications entirely in the Go programming language. It eliminates the need for a separate JavaScript/TypeScript toolchain and brings the benefits of Go's simplicity, performance, and type safety to the world of frontend development.
- β Pure Go Frontend: Write your UI components, state management, and application logic in 100% Go.
- β Type Safety: Catch errors at compile time, not runtime, with Go's static typing across your entire stack.
- β Reactivity Model: A simple and powerful observable-based state management system to build dynamic interfaces.
- β Virtual DOM: Efficiently updates the browser's DOM by calculating and applying minimal changes.
- β
CLI Tooling: A simple
golemcommand to create, run, and build your projects. - β
Zero JS Dependencies: The final build is a static
index.html, awasm_exec.jshelper, and your compiledapp.wasm.
Golem's architecture is designed to be simple and transparent. The following diagrams illustrate the key concepts.
This diagram shows the high-level view of the Golem ecosystem, from development to the final application running in the browser.
graph TD
subgraph "Development Environment"
direction LR
DevCode["Go Source Code<br>(src/app/main.go)"]
CLI["Golem CLI<br>(./golem)"]
DevCode -- "golem dev" --> CLI
end
subgraph "Build Process (Handled by 'golem dev')"
direction TB
CLI --> GoCompiler["Go Compiler<br>(tinygo)"]
GoCompiler -- "Compiles to" --> Wasm["WebAssembly Module<br>(.golem/dev/app.wasm)"]
CLI --> DevServer["Development Web Server"]
Wasm -- "Served with" --> DevServer
JSHelper["wasm_exec.js<br>(Go WASM Helper)"] -- "Served by" --> DevServer
end
subgraph "Browser Environment (Client-Side)"
direction TB
DevServer -- "HTTP Request" --> Browser["User's Browser"]
Browser -- "Loads" --> JSHelper
Browser -- "Loads & Instantiates" --> Wasm
Wasm -- "Executes Go main()" --> GoApp["Go Application Logic<br>(Running in WASM)"]
GoApp -- "Manipulates DOM via" --> VDOM["Golem Virtual DOM"]
end
subgraph "User Interface"
VDOM -- "Renders & Patches" --> RealDOM["Live HTML DOM<br>(What the user sees)"]
end
style DevCode fill:#f0f8ff,stroke:#4a90e2
style CLI fill:#f0f8ff,stroke:#4a90e2
style GoCompiler fill:#fffbe6,stroke:#f5a623
style Wasm fill:#fffbe6,stroke:#f5a623
style DevServer fill:#fffbe6,stroke:#f5a623
style JSHelper fill:#fffbe6,stroke:#f5a623
style Browser fill:#e6ffed,stroke:#7ed321
style GoApp fill:#e6ffed,stroke:#7ed321
style VDOM fill:#e6ffed,stroke:#7ed321
style RealDOM fill:#d4edda,stroke:#155724
This diagram details how Golem's reactive state management works. When an event updates the application state, the UI automatically reflects the change through a one-way data flow.
graph TD
subgraph "User Interaction"
User["User"] -- "Clicks Button" --> DOMButton["DOM Button Element"];
end
subgraph "Event Handling (Go in WASM)"
DOMButton -- "Triggers 'onclick'" --> GoCallback["Go OnClick Callback"];
GoCallback -- "Calls" --> StateSet["state.Set(newValue)"];
end
subgraph "State Management (Observable)"
StateSet -- "Updates" --> Observable["Observable<T><br><i>Holds application state</i>"];
Observable -- "Notifies" --> Subscriptions["Registered Subscriptions<br><i>(Callbacks)</i>"];
end
subgraph "UI Update"
Subscriptions -- "Execute" --> UIUpdateFn["UI Update Function"];
UIUpdateFn -- "Calls" --> ElementUpdate["element.Update(...)"];
end
subgraph "Virtual DOM Diffing & Patching"
ElementUpdate -- "Calculates minimal change" --> VDOM["Virtual DOM"];
VDOM -- "Generates JS call" --> Patch["DOM Patch<br><i>e.g., element.textContent = 'new'</i>"];
Patch -- "Applies changes to" --> RealDOM["Real DOM"];
end
subgraph "Visual Feedback"
RealDOM -- "Renders update" --> User;
end
style User fill:#fce8e6,stroke:#d93025
style DOMButton fill:#e8f0fe,stroke:#4285f4
style GoCallback fill:#e6f4ea,stroke:#34a853
style StateSet fill:#e6f4ea,stroke:#34a853
style Observable fill:#fef7e0,stroke:#fbbc04
style Subscriptions fill:#fef7e0,stroke:#fbbc04
style UIUpdateFn fill:#e8f0fe,stroke:#4285f4
style ElementUpdate fill:#e8f0fe,stroke:#4285f4
style VDOM fill:#d1e2ff,stroke:#4a90e2
style Patch fill:#fce8e6,stroke:#d93025
style RealDOM fill:#e8f0fe,stroke:#4285f4
# Navigate to your project directory first
mkdir my-project && cd my-project
# Install golem locally in this directory
curl -sSL https://raw.githubusercontent.com/Nu11ified/golem/main/install.sh | bashThis script automatically detects your OS/architecture and installs golem in your current directory.
- Go to the releases page
- Download the appropriate binary for your platform (auto-built for all platforms)
- Extract the archive and move the binary to your PATH
git clone https://github.com/Nu11ified/golem.git
cd golem
go build -o golem ./cmd/golem/main.go# Create a new project in current directory
./golem new my-golem-app
# Navigate to the project
cd my-golem-app
# Copy golem binary to the new project
cp ../golem .
# Start the development server
./golem devThe server will start, compile your Go application to WebAssembly, and serve it. You can now access your application at http://localhost:3000.
Choose one of the installation methods above to get the golem CLI tool.
Use the CLI to create a new Golem application.
./golem new my-golem-appNavigate into your new project, copy the golem binary, and start the development server.
cd my-golem-app
cp ../golem .
./golem devThe server will start, compile your Go application to WebAssembly, and serve it. You can now access your application at http://localhost:3000.
Here is a simplified version of a data-fetching application to demonstrate Golem's core concepts.
File: src/app/main.go
package main
import (
"fmt"
"syscall/js"
"github.com/Nu11ified/golem/dom"
"github.com/Nu11ified/golem/state"
)
func App() *dom.Element {
// 1. Define reactive state for the counter
count := state.NewObservable(0)
// 2. Create a text node that will display the count
// We will update this element directly when the state changes.
countText := dom.Text(fmt.Sprintf("Current count: %d", count.Get()))
// 3. Subscribe to state changes
// This function runs whenever count.Set() is called.
count.Subscribe(func(newValue, _ int) {
// Update the text node's content directly
countText.Update(map[string]interface{}{
"textContent": fmt.Sprintf("Current count: %d", newValue),
})
})
// 4. Return the element tree
return dom.Div(
dom.H1("Golem Counter Example"),
dom.P(countText), // Embed the reactive text node
dom.Button(
"Increment",
dom.OnClick(func() {
// Increment the state, which triggers the subscription
count.Set(count.Get() + 1)
}),
),
dom.Button(
"Decrement",
dom.OnClick(func() {
count.Set(count.Get() - 1)
}),
),
)
}
func main() {
// Render the main App component into the DOM element with id="app"
dom.Render(App(), "#app")
// Prevent the Go program from exiting, which is necessary for WASM apps
select {}
}| Command | Description |
|---|---|
golem new <name> |
Creates a new Golem project in a directory with the given name. |
golem dev |
Starts the development server, watches for file changes, and rebuilds. |
golem build |
(Coming Soon) Bundles the application for production. |
golem version |
Prints the version of the Golem CLI. |
This project uses automated releases! Binaries are automatically built for all platforms when code is pushed.
To trigger a new release, use conventional commit messages:
# Bug fixes (patch version)
git commit -m "fix: resolve authentication issue"
# New features (minor version)
git commit -m "feat: add dark mode support"
# Breaking changes (major version)
git commit -m "feat!: redesign API structure"Every commit to main automatically builds and tests on all platforms. Release binaries include Linux (x64/ARM64), macOS (Intel/Apple Silicon), and Windows (x64).
Golem is currently in a highly experimental, proof-of-concept stage. The API is subject to change. It is not yet ready for production use but is a great environment for experimenting with the future of web development in Go.
- v0.2: Stabilize the core
domandstateAPIs. - v0.3: Implement a robust component lifecycle system.
- v0.4: Introduce a CSS-in-Go styling solution.
- v0.5: Add a client-side router.
- v1.0: Production-ready release.
This project is in its early stages, and contributions are highly welcome! Whether it's bug reports, feature suggestions, or code contributions, please feel free to open an issue or pull request.
Use conventional commit messages to trigger automatic releases when your changes are ready.
This project is licensed under the MIT License - see the LICENSE file for details.
