nojs is a high-performance, AOT-compiled web framework that allows you to build sophisticated front-end applications entirely in Go. By treating the Go compiler as your "Inspector," nojs eliminates entire classes of runtime errors through strict type-safety and a familiar, idiomatic developer experience.
⚠️ Project Status: This is an MVP (Minimum Viable Product) and is not production-ready. The API may change, and some features are still in active development. Use for experimentation and feedback.
- 🔒 Type-Safe Templates - Compile-time validation of props, methods, and expressions
- ⚡ Virtual DOM - Efficient diffing and patching for minimal DOM operations
- 🧩 Component Model - Reusable UI building blocks with Go structs and HTML templates
- 🗺️ Built-in Router - SPA routing with layout support and nested routes
- 📋 Optimized Lists -
trackBykeys for efficient list updates and re-rendering - 🎯 Event Handling - Type-safe event binding validated at compile time
- 🚀 WebAssembly - Near-native performance in the browser via Go WASM
- 🛠️ AOT Compilation - Template parsing at build time, not runtime
Every feature in nojs is guided by principles designed for developers who value stability and performance over "magic."
-
Type Safety Above All: We prefer compile-time safety over runtime flexibility. Our AOT compiler validates props, methods, and expressions before they ever reach the browser.
-
Go-Idiomatic by Default: Templates and component architectures feel like natural extensions of Go. Syntax patterns (like
for...range) are modeled directly on Go semantics. -
Explicit > Implicit: We favor clarity and control. Features like manual state updates (
StateHasChanged()) and mandatory list keys (trackBy) make data flow predictable and easy to debug. -
Simplicity Through Focus: A lean, focused API that avoids complexity for little practical benefit.
-
Unopinionated Foundation: We provide the core (rendering, lifecycle, type-safety) but leave state management and project structure to you.
For the full principles behind these decisions, read the NoJS Manifesto.
This is a "free time" project. Whether you're a senior dev or someone just starting with Go or WASM, there is zero pressure here.
We don't have a corporate roadmap or investors to answer to. We care about building the framework correctly, not quickly. Contributions are welcomed at whatever pace your life allows.
Want to see nojs in action? Check out the interactive demo at forgelogic.github.io/nojs/demo.
The demo showcases core framework features—components, routing, event handling, and list rendering—all running entirely in Go-compiled WebAssembly.
- Go 1.25+
- Make
- Python 3 (required for
make serve, or use any static file server of your choice)
For detailed instructions on running the demo app, see the Getting Started Guide.
See the Installation Guide for a step-by-step guide to creating a new project using the demo app as a scaffold.
The repository is organized as a Go workspace:
nojs/— Core framework code (runtime, VDOM)compiler/— AOT template compiler (nojsc), maintained as a separate modulerouter/— SPA routing engine, maintained as a separate moduleapp/— Example application demonstrating framework features (also the recommended project scaffold)go.work— Workspace configuration linking all modules
The framework (github.com/ForgeLogic/nojs), compiler (github.com/ForgeLogic/nojs/compiler), router (github.com/ForgeLogic/nojs/router), and app (github.com/ForgeLogic/app) are separate modules that work together during development.
Note: The compiler, router, and demo app are currently co-located in this repository for convenience during active development. Once each reaches a stable API, it will be moved to its own dedicated repository.
| Command | Action |
|---|---|
make full |
Compiles templates + WASM (Development) |
make full-prod |
Compiles templates + WASM (Production/Optimized) |
make wasm |
Rebuilds WASM only (Fast: ~1-2 seconds) |
make serve |
Starts development server on port 9090 |
make clean |
Removes generated WASM binaries |
Tip: Enable "Disable cache" in your browser's DevTools Network tab to ensure the WASM module reloads on every refresh.
The heart of nojs is its Ahead-of-Time compiler. It transforms declarative HTML templates (.gt.html) into high-performance Go component code.
The compiler scans directories for *.gt.html files and auto-generates corresponding .generated.go files with Render() methods.
-
Create your component:
MyComponent.gt.html- HTML template with Go expressionsmycomponent.go- Go struct with state and event handlers
-
Compile templates:
Bash
# Compile all templates in the components directory make full # Or run the compiler directly go run github.com/ForgeLogic/nojs/cmd/nojs-compiler -in ./app/internal/app/componentsThis generates
MyComponent.generated.gowith theRender()method. -
Use the component: Import and instantiate your component like any Go struct. The framework handles rendering, diffing, and updates.
-in <directory>- Source directory to scan for*.gt.htmlfiles-dev- Enable development mode (verbose errors, warnings)
Here's a simple counter component to illustrate the framework:
counter.go:
package components
import "github.com/ForgeLogic/nojs/runtime"
type Counter struct {
runtime.ComponentBase
Count int
}
func (c *Counter) Increment() {
c.Count++
c.StateHasChanged() // Trigger re-render
}
func (c *Counter) Decrement() {
c.Count--
c.StateHasChanged() // Trigger re-render
}Counter.gt.html:
<div class="counter">
<h2>Count: {Count}</h2>
<button @onclick="Increment">+</button>
<button @onclick="Decrement">-</button>
</div>Full documentation is available at forgelogic.github.io/nojs.
nojs is an open-source project. We welcome contributions from developers who share our passion for type-safe, performant web tools.
For detailed contribution guidelines, see CONTRIBUTING.md.
Distributed under the Apache License 2.0. See LICENSE for more information.