A modern Progressive Web Application (PWA) template built entirely in Go, featuring a SQLite-backed key/value store (with optional Litestream S3 replication) and a WebAssembly-powered frontend.
This template provides a full-stack Go application with:
- Frontend: Pure Go PWA using go-app framework compiled to WebAssembly
- Backend: HTTP server with RESTful API endpoints
- Database: SQLite-backed key-value storage (configured via
DATABASE_PATH) - Backups: Optional Litestream streaming replication to Amazon S3
- Build System: Dual compilation for server and WASM client
- go-app: Progressive Web App framework for Go
- SQLite (modernc.org/sqlite): Embedded data store accessed through Go's
database/sql - Litestream: Optional SQLite WAL replication to S3 when environment variables are set
- WebAssembly: Client-side Go code compiled to WASM
- Go 1.24.1: Latest Go version with enhanced WASM support
go-everywhere/
├── main.go # Server-side entry point (!js build tag)
├── main_js.go # Client-side entry point (js build tag)
├── database.go # SQLite configuration/bootstrap
├── api/ # REST API endpoints
│ ├── users.go # User CRUD operations
│ └── message.go # Message API handler
├── db/ # Database client layer
│ ├── client.go # SQLite key/value helper
│ ├── schema.go # Schema management helpers
│ └── errors.go # Custom error types
├── models/ # Data models
│ └── user.go # User model
├── views/ # PWA page components
│ ├── home.go # Home page view
│ └── profile.go # Profile page view
├── widgets/ # Reusable UI components
│ └── header.go # Navigation header widget
├── web/ # Compiled WASM output
│ └── app.wasm # WebAssembly binary
├── CLUSTER.md # Clustering deployment guide
├── Makefile # Build commands
└── README.md # Project documentation
- Single Page Application with client-side routing
- Offline capability through service workers
- Installable on desktop and mobile devices
- Responsive design ready
- DATABASE_PATH environment variable controls the on-disk SQLite file (defaults to
data/app.db) - Uses a simple key/value table that stores JSON payloads per namespace
- Runs with WAL mode and busy timeouts for smooth concurrent access
- Set the
LITESTREAM_*environment variables to stream real-time backups to Amazon S3
- Server Binary: Full Go backend backed by SQLite and REST APIs
- WASM Binary: Client-side Go compiled to WebAssembly
- Build tags (
//go:build jsand//go:build !js) for conditional compilation - Shared view components between server and client
- Reusable UI widgets (Header, etc.)
- Composable view components
- Type-safe component properties
- Server-side rendering capability
- Go 1.24.1 or higher
- Make (for build automation)
- Clone the repository:
git clone https://github.com/go-everywhere/go-everywhere.git
cd go-everywhere- Install dependencies:
go mod downloadBuild both server and WASM client:
make buildThis will:
- Compile the WASM client to
web/app.wasm - Build the server binary
Start the server:
go run .Or after building:
./go-everywhereThe application will be available at http://localhost:8000
- Create a new view component in
views/:
package views
import (
"github.com/maxence-charriere/go-app/v10/pkg/app"
)
type MyPage struct {
app.Compo
}
func (p *MyPage) Render() app.UI {
return app.Section().Body(
// Your UI components
)
}- Register routes in both
main.goandmain_js.go:
// main.go (server-side)
app.Route("/mypage", func() app.Composer {
return &views.MyPage{}
})
// main_js.go (client-side)
app.Route("/mypage", func() app.Composer {
return &views.MyPage{}
})Create new handlers in api/:
func MyHandler(client *db.Client) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// Handler logic using the database client
}
}Register in main.go:
http.HandleFunc("/api/myendpoint", api.MyHandler(client))The database client provides simple key-value operations:
// Store data
err := client.Put(ctx, "namespace", "key", value)
// Retrieve data
data, err := client.Get(ctx, "namespace", "key")
// Delete data
deleted, err := client.Delete(ctx, "namespace", "key")
// Get all keys in namespace
allData, err := client.GetAll(ctx, "namespace")Set the DATABASE_PATH environment variable to control where the SQLite database file lives. If omitted, the app writes to data/app.db relative to the working directory and creates the folder when needed:
export DATABASE_PATH=./data/app.db
The schema is created automatically on startup, and the database runs with WAL mode plus a sensible busy timeout for concurrent access.
Streaming replication is enabled automatically whenever a bucket is provided:
LITESTREAM_BUCKET(required) – name of the S3 bucketLITESTREAM_PATH(optional) – prefix within the bucket; defaults to the database file nameLITESTREAM_REGION,LITESTREAM_ENDPOINT,LITESTREAM_FORCE_PATH_STYLE,LITESTREAM_SKIP_VERIFY(optional) – advanced S3 configurationLITESTREAM_ACCESS_KEY_IDandLITESTREAM_SECRET_ACCESS_KEY(optional) – otherwise the AWS SDK uses its default credential chain
Once these variables are present, Litestream will tail the SQLite WAL and upload snapshots/WAL frames in the background.
You can inspect the local SQLite file directly:
sqlite3 data/app.db 'SELECT namespace, key, value FROM app_kv ORDER BY updated_at DESC;'
The test suite provisions a temporary SQLite database automatically (t.TempDir()), so no additional services or environment variables are required.
- (Optional) Provision an S3 bucket for Litestream backups and store the
LITESTREAM_*secrets. - Deploy with
fly deploy– no external database is required.
The Dockerfile builds both the WebAssembly bundle and the HTTP server so no extra build steps are required in production.