GoFlare is a self-contained Go tool (library + CLI) for deploying Go WASM projects to Cloudflare Workers and Pages. No Node.js, no Wrangler. Pure Go, direct Cloudflare API. Deploy runs in GitHub Actions — secrets never touch the developer's machine.
- Cloudflare Pages Functions in Go (recommended) — static site + Go edge function deployed via CF Git Integration
- Standalone Cloudflare Workers in Go (WASM)
- Static Cloudflare Pages (Go WASM frontends)
The project mode is inferred from edge/main.go imports — no MODE variable in .env. See BUILD_PAGES_FUNCTIONS.md.
my-project/
├── .env # credentials — gitignored (NEVER tokens)
├── .env.example
├── routes/
│ └── routes.go # build-agnostic — func Register(r router.Router)
├── modules/
│ └── contact/
│ ├── model.go # build-agnostic — model + Validate()
│ └── handler.go # build-agnostic — func Handle(ctx router.Context)
├── web/
│ ├── client.go # //go:build wasm — frontend (browser)
│ ├── server.go # //go:build !wasm — local dev server
│ └── public/ # static assets — committed; produced by tinywasm framework
│ ├── index.html
│ ├── client.wasm
│ ├── script.js
│ └── style.css
├── edge/
│ └── main.go # //go:build wasm — entrypoint, imports goflare/pages
└── functions/ # generated by goflare — COMMITTED
├── [[path]].mjs # catch-all glue (exports onRequest)
└── edge.wasm # compiled edge/main.go
PROJECT_NAME=my-app
# DOMAIN=example.com # optional, custom domain for PagesCLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID are secrets — they live in GitHub Secrets, never in .env.
Install the CLI:
go install github.com/tinywasm/goflare/cmd/goflare@latestgoflare auth --check: ValidateCLOUDFLARE_API_TOKENfrom environment.goflare build: Infer mode fromedge/main.goimports and produce artifacts.goflare deploy: Direct Upload v2.⚠️ Designed for CI/CD environments. Now includes automatic Pages project provisioning and robust error reporting.
Deployment is designed to run in CI. Register secrets in: GitHub → Settings → Secrets and variables → Actions.
| Name | Type | Description |
|---|---|---|
CLOUDFLARE_API_TOKEN |
Secret | API Token with Workers and Pages permissions |
CLOUDFLARE_ACCOUNT_ID |
Secret | Your Cloudflare Account ID |
D1_DATABASE_ID |
Variable | D1 database ID (optional) |
For more details see CI_D1_SECRETS.md.
edge/main.go:
//go:build wasm
package main
import (
"github.com/tinywasm/goflare/pages" // ← this import sets MODE=pages-functions
"github.com/your-project/routes"
)
func main() {
r := pages.NewRouter()
routes.Register(r)
pages.Serve(r)
}Files with //go:build wasm (everything under edge/, routes/, modules/, workers/, pages/pages.go, cloudflare/env_wasm.go) NEVER import fmt, strings, errors, encoding/*, net/http, log, io/ioutil. Use tinywasm/fmt, tinywasm/json, tinywasm/strings, tinywasm/fetch instead.
Stdlib inflates the wasm binary ~80% and exceeds Cloudflare Free's 1 MiB limit. TinyGo also does not fully support net/http in js/wasm.
Verification: grep -rE '^\s*"(fmt|strings|errors|encoding|net/http|log|io/ioutil)"' edge/ routes/ modules/ workers/ pages/pages.go cloudflare/env_wasm.go must return empty.
cfg := &goflare.Config{
ProjectName: "myapp",
AccountID: "acc-id",
}
g := goflare.New(cfg)
g.Build()
g.Deploy()| Field | .env key | Default | Notes |
|---|---|---|---|
ProjectName |
PROJECT_NAME |
— | required |
AccountID |
GitHub Secret CLOUDFLARE_ACCOUNT_ID |
— | required |
WorkerName |
WORKER_NAME |
<ProjectName>-worker |
optional |
Entry |
— | auto: edge |
Convention: edge/main.go |
PublicDir |
— | auto: web/public |
Convention: web/public |
Domain |
DOMAIN |
— | optional custom domain |
CompilerMode |
COMPILER_MODE |
S |
S=small/prod, M=debug, L=Go std |
- Go 1.25.2+
- TinyGo — installed automatically by
goflare buildviatinywasm/tinygo