Gutter
v0.6.0 · Full-stack Go → WebAssembly

Declarative web UI, written in Go.

Compose your interface from widgets — Flutter-inspired. Render the first paint on the server, then hydrate to WebAssembly that drives the browser DOM directly. No npm, no webpack, no node_modules.

package main

import (
    "github.com/Runway-Club/gutter"
    "github.com/Runway-Club/gutter/themes"
    "github.com/Runway-Club/gutter/widgets"
)

type App struct{}

func (App) Build(ctx *gutter.BuildContext) gutter.Widget {
    return widgets.Scaffold{
        Theme:  themes.Apple,
        AppBar: widgets.AppBar{Title: "Hello"},
        Body: widgets.Center{
            Child: widgets.Button{
                Variant: widgets.ButtonPrimary,
                Label:   "Get started",
            },
        },
    }
}

func main() { gutter.RunApp(App{}) }

One language, all the way down

Share types and validation between server and UI — the same widget tree renders on the server and hydrates in the browser. The only JavaScript you ship is the tiny wasm_exec.js glue from the Go toolchain.

code
Pure Go, top to bottom

Widgets, state, and layout are plain Go structs and methods. Your editor, go vet, and the type checker work exactly as they always have.

bolt
Compiles to WebAssembly

go build -o app.wasm with GOOS=js GOARCH=wasm. The runtime mounts a persistent element tree and drives the DOM directly.

palette
Theme-driven styling

Pick a variant — ButtonPrimary, CardFeature — and the active theme supplies the values. No CSS in application code.

compress
Tiny bundles with TinyGo

Opt into --tinygo for 4–8× smaller WebAssembly. A counter app drops from ~2.8 MB to ~340 KB.

sync
Surgical re-renders

SetState rebuilds only the subtree that owns the state. Siblings, focused inputs, and scroll positions stay untouched.

rocket_launch
Batteries-included CLI

gutter new scaffolds, gutter run dev gives live reload, gutter build deploy emits a Dockerfile + nginx image.

dns
Server-side rendering

Render the first paint as HTML for instant load and SEO, then the same widget tree hydrates to WebAssembly in place. One main() drives both client and server — gutter.Serve.

swap_horiz
Typed client↔server RPC

Define request and response structs once in a shared package; rpc.Handle on the server, rpc.Call on the client. No codegen, no stringly-typed routes — renaming a field is a compile error on both sides.

widgets
Interactive islands

Drop independent Gutter widgets into an existing HTML or SSR page. Each island lazy-loads the WebAssembly only when it scrolls into view, so mostly-static pages stay light.

This page is the demo

Everything you're looking at is one Gutter widget tree. The counter below is a StatefulWidget — tapping it rebuilds only its own card, leaving the rest of the page (and your scroll position) untouched.

Stateful counter

0

Tapping these only rebuilds this card.

A familiar model

Three widget kinds over a persistent element tree, the way Flutter and React do it. Stateless composes, Stateful owns mutable state, Host maps to one DOM node.

type Counter struct{}

func (Counter) CreateState() gutter.State { return &counterState{} }

type counterState struct {
    gutter.StateObject
    count int
}

func (s *counterState) Build(ctx *gutter.BuildContext) gutter.Widget {
    return widgets.Button{
        Label:     fmt.Sprintf("Count: %d", s.count),
        OnPressed: func() { s.SetState(func() { s.count++ }) },
    }
}
check_circle

Embed gutter.StateObject by value; return your state by pointer from CreateState.

check_circle

SetState(fn) mutates state, then reconciles only this element's subtree.

check_circle

Anything touching syscall/js lives behind a //go:build js && wasm tag — app code stays platform-neutral.

Ship your first app in a minute

# 1. install the CLI
go install github.com/Runway-Club/gutter/cmd/gutter@latest

# 2. scaffold a project (add --ssr for a server-rendered + typed-RPC starter)
gutter new myapp && cd myapp

# 3. run with live reload at http://localhost:8080
gutter run dev
Browse examples →

Gutter — a Flutter-inspired UI library for Go. MIT © Runway Club.