GoFlare is a self-contained Go tool (library + CLI) for deploying Go WASM projects to Cloudflare Workers and Pages. No Node.js, no Wrangler, no GitHub Actions. Pure Go, direct Cloudflare API.
- Deploying Cloudflare Workers written in Go (WASM)
- Deploying Cloudflare Pages (Static sites or Go WASM frontends)
- Full-stack Go WASM projects (Frontend + Edge Backend)
The following structure is recommended and auto-detected by GoFlare:
my-project/
├── .env # credentials — gitignored
├── .env.example # public template
├── modules/
│ └── contact/
│ ├── model.go # shared models — build-agnostic
│ └── model_orm.go # generated by ormc
├── web/
│ ├── client.go # //go:build wasm — frontend (browser)
│ ├── server.go # //go:build !wasm — local dev server
│ └── public/ # PUBLIC_DIR — deployed as-is to Cloudflare Pages
│ ├── index.html
│ ├── client.wasm # generated by goflare build
│ ├── script.js # generated by goflare build
│ └── style.css # generated by goflare build
├── edge/
│ └── main.go # //go:build wasm — edge function (Cloudflare Worker)
│ # auto-detected: no ENTRY= in .env needed
└── .build/ # OutputDir — gitignored, worker artifacts only
├── edge.js
└── edge.wasm
Create a .env file in your project root:
PROJECT_NAME=my-app
CLOUDFLARE_ACCOUNT_ID=your-account-id
PUBLIC_DIR=web/public
# ENTRY=edge # Optional: auto-detected if edge/main.go exists
# DOMAIN=example.com # Optional: custom domain for PagesInstall the CLI:
go install github.com/tinywasm/goflare/cmd/goflare@latestgoflare init: Setup project and .envgoflare build: Compile WASM and generate assetsgoflare deploy: Deploy to Cloudflare
Minimal working edge/main.go using workers.Handle:
//go:build wasm
package main
import "github.com/tinywasm/goflare/workers"
func main() { workers.Handle(handler) }
func handler(w *workers.Response, r *workers.Request) {
w.Header()["Content-Type"] = "application/json"
w.WriteHeader(200)
w.Write([]byte(`{"ok":true}`))
}Note: auto-detected, no ENTRY= needed if using the edge/ directory.
Minimal working web/client.go:
//go:build wasm
package main
import (
"github.com/tinywasm/dom"
"github.com/tinywasm/form"
)
type MyForm struct {
Name string `input:"required"`
}
func main() {
data := &MyForm{}
f, _ := form.New("app", data)
dom.Render("app", f)
select {}
}Note: compiled to web/public/client.wasm.
Shared models live in modules/ and can be imported by both frontend and edge.
package contact
// ormc:formonly
type ContactForm struct {
Nombre string `input:"required,min=2"`
Email string `input:"email,required"`
Mensaje string `input:"textarea,required,min=10"`
}cfg := &goflare.Config{
ProjectName: "myapp",
AccountID: "acc-id",
PublicDir: "web/public",
}
g := goflare.New(cfg)
g.Build()
store := goflare.NewKeyringStore()
g.Deploy(store)| Field | .env key | Default | Notes |
|---|---|---|---|
ProjectName |
PROJECT_NAME |
— | required |
AccountID |
CLOUDFLARE_ACCOUNT_ID |
— | required |
WorkerName |
WORKER_NAME |
<ProjectName>-worker |
optional |
Entry |
ENTRY |
auto: edge if edge/main.go exists |
directory name, not a file |
PublicDir |
PUBLIC_DIR |
— | required for Pages deploy |
Domain |
DOMAIN |
— | optional custom domain |
CompilerMode |
COMPILER_MODE |
S |
S=small/prod, M=debug, L=Go std |
At least one of
EntryorPublicDirmust be set.
After goflare build:
web/public/: Pages source (index.html, client.wasm, script.js, style.css).build/: Worker artifacts (edge.js, edge.wasm)- NO
dist/directory is created.
S: Small (TinyGo production, minified)M: Medium (TinyGo debug)L: Large (Go standard compiler)
- Go 1.25.2+
- TinyGo — installed automatically by
goflare buildviatinywasm/tinygo
goflare calls tinygo.EnsureInstalled() before each Worker build. If TinyGo is already in PATH at the correct version, nothing happens. If it is missing or outdated, it is downloaded and installed to the local cache automatically.
To manage TinyGo independently:
import "github.com/tinywasm/tinygo"
tinygo.EnsureInstalled()
env := tinygo.GetEnv()See goflare-demo for a complete example.