Gux
A full-stack Go framework for building modern web applications with WebAssembly. Write your entire application in Go — from type-safe API clients to reactive UI components.
Live Demo — Try Gux in your browser
Features
- Type-Safe API Generation — Define Go interfaces, generate HTTP clients and server handlers automatically
- Universal Rendering — SSR + WASM hydration with the core framework
- CRUD API Generation — Automatic REST endpoints from GORM models with DTOs
- CSRF Protection — Automatic Double Submit Cookie pattern for all mutations
- Server Utilities — Middleware composition, SPA handler, CORS, logging, and error handling
- Go-Powered Frontend — Compile to WebAssembly, run natively in the browser
Quick Start
Prerequisites
- Go 1.21+
- TinyGo 0.30+ (optional, for smaller WASM builds ~500KB vs ~5MB)
Installation
# Install the Gux CLI tool
go install github.com/dougbarrett/gux/cmd/gux@latestCreate a New App
# Scaffold a new application gux init --module github.com/youruser/myapp myapp # Run development server cd myapp gux dev # Build and run at http://localhost:8080
This creates a minimal Gux application with:
cmd/app/main.go— WASM frontend with router and layoutcmd/server/main.go— HTTP server with SPA handlerinternal/api/— Example API interface for code generationDockerfile— Multi-stage Docker build
Default files (index.html, manifest.json, service-worker.js, wasm_exec.js) are automatically injected at build time. To customize the HTML shell, create a public/ directory with your own files.
Generate API Code
# Generate client and server code from API interfaces gux gen # Scans ./api directory gux gen --dir src/api # Custom directory
This finds all .go files with @client annotations and generates type-safe HTTP clients and server handlers.
Run the Example
cd example make dev-tinygo # Build and start server # Open http://localhost:8093
How It Works
1. Define Your API Interface
// api/posts.go package api import "context" // @client PostsClient // @basepath /api/posts type PostsAPI interface { // @route GET / GetAll(ctx context.Context) ([]Post, error) // @route GET /{id} GetByID(ctx context.Context, id int) (*Post, error) // @route POST / Create(ctx context.Context, req CreatePostRequest) (*Post, error) // @route PUT /{id} Update(ctx context.Context, id int, req CreatePostRequest) (*Post, error) // @route DELETE /{id} Delete(ctx context.Context, id int) error }
2. Generate Client & Server Code
This scans the api/ directory and generates:
posts_client_gen.go— Type-safe HTTP client for WASMposts_server_gen.go— HTTP handler with automatic routing
3. Build Your Frontend
See the examples/minimal directory for a complete reference implementation with:
- Hybrid rendering — SSR + WASM hydration
- Route groups — Public and admin routes with separate WASM bundles
- CRUD with DTOs — Users and Posts with secure field filtering
- State management — Server-side data loading with client hydration
4. Compile to WebAssembly
# Standard Go (larger output, ~5MB) GOOS=js GOARCH=wasm go build -o main.wasm ./app # TinyGo (smaller output, ~500KB) tinygo build -o main.wasm -target wasm -no-debug ./app
5. Create Your Server
package main import ( "net/http" "yourapp/api" "github.com/dougbarrett/gux/server" ) func main() { mux := http.NewServeMux() // Wire up generated handler with your service service := NewPostsService() handler := api.NewPostsAPIHandler(service) // Add middleware handler.Use( server.Logger(), server.CORS(server.CORSOptions{}), server.Recover(), ) handler.RegisterRoutes(mux) // Serve static files with SPA routing spa := server.NewSPAHandler("./static") mux.HandleFunc("/", spa.ServeHTTP) http.ListenAndServe(":8080", mux) }
Documentation
| Guide | Description |
|---|---|
| Getting Started | Installation, setup, and first app |
| API Generation | Code generation annotations and usage |
| Templates | Page templates and patterns |
| Server Utilities | Middleware and backend helpers |
| Deployment | Docker and production setup |
Core Framework
The core/ package provides universal rendering that works identically on server (SSR) and client (WASM):
import "github.com/dougbarrett/gux/core" func MyPage(r *core.Router) func() core.Node { // Loader: runs on server for SSR, via API for client navigation var items []Item r.OnLoad(func() { // Fetch data }) // Component: returns UI, re-runs on state changes return func() core.Node { count := r.StateInt("count", 0) return core.Div(core.Class("container"), core.H1(core.Attrs{}, core.Text("Items")), core.Button(core.Attrs{ OnClick: func() { count.Set(count.Get() + 1) }, }, core.Text("Increment")), ) } }
See examples/minimal for complete patterns and best practices.
State Management
import "github.com/dougbarrett/gux/core" func MyPage(r *core.Router) func() core.Node { return func() core.Node { // Typed state helpers count := r.StateInt("count", 0) name := r.StateString("name", "") active := r.StateBool("active", false) // Generic state for any type user := core.UseState(r, "user", User{Name: "Guest"}) // Read state current := count.Get() // Update state (triggers re-render) count.Set(current + 1) // Update without re-render name.SetQuiet("new value") return core.Div(core.Class("container")) } }
Server Utilities
Middleware
// Compose middleware handler := server.Chain( server.Logger(), // Request logging server.CORS(opts), // Cross-origin support server.Recover(), // Panic recovery server.RequestID(), // X-Request-ID header )(apiHandler)
Error Handling
// Structured errors with HTTP status codes if user == nil { return nil, api.NotFoundf("user %d not found", id) } if !valid { return nil, api.BadRequest("invalid email format") } // Automatic JSON error responses // {"error": {"code": "not_found", "message": "user 123 not found"}}
Pagination
func handleList(w http.ResponseWriter, r *http.Request) { q := api.Query(r) search := q.String("search", "") page := q.Pagination() // Reads ?page=1&per_page=20 items := fetchItems(search, page.Offset, page.PerPage) total := countItems(search) result := api.NewPaginatedResult(items, page, total) json.NewEncoder(w).Encode(result) }
Project Structure
gux/
├── api/ # Error handling, query utilities, pagination
├── cmd/gux/ # CLI tool (gux init, gux gen)
├── core/ # Universal rendering framework (SSR + WASM)
├── examples/ # Reference implementations
│ └── minimal/ # Complete app with hybrid rendering
├── fetch/ # Browser fetch API wrapper with CSRF
└── server/ # Middleware and SPA handler
Deployment
Docker
cd example make docker # Build image make docker-run # Run locally on :8080
The Dockerfile uses multi-stage builds:
- TinyGo — Compiles WASM frontend (~500KB)
- Go — Builds server binary
- Alpine — Minimal production image (~20MB)
See Deployment Guide for Kubernetes, fly.io, and other platforms.
PWA Support
Gux applications can be installed as Progressive Web Apps:
- Installable — Add to home screen on mobile and desktop
- Offline Support — Service worker caches static assets
- Asset Caching — Cache-first strategy for optimal performance
The example application includes:
manifest.json— App metadata, icons, theme colorssw.js— Service worker with intelligent caching- Install prompt component with 7-day dismissal cooldown
# PWA files are in example/server/static/
example/server/static/manifest.json
example/server/static/sw.jsContributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
License
MIT License — see LICENSE for details.
