GoFlare is a self-contained Go tool (library + CLI) for deploying Go WASM projects to Cloudflare Workers and static assets. No Node.js, no Wrangler. Pure Go, direct Cloudflare API. Deploy runs in GitHub Actions — secrets never touch the developer's machine.
- Cloudflare Worker with Static Assets (recommended) — static site + Go edge function deployed in a single Cloudflare Worker.
- Standalone Cloudflare Workers in Go (WASM).
- Static Cloudflare Sites (Go WASM frontends).
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 webtyp framework
│ ├── index.html
│ ├── client.wasm
│ ├── script.js
│ └── style.css
├── edge/
│ └── main.go # //go:build wasm — entrypoint, imports webtyp/cloudflare/edge or cloudflare/workers
└── .build/ # generated by goflare
├── edge.js # JS glue bundle
└── edge.wasm # compiled edge/main.go
PROJECT_NAME=my-app
# DOMAIN=example.com # optional custom domainCLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID are secrets — they live in GitHub Secrets, never in .env.
Install the CLI:
go install webtyp.com/goflare/cmd/goflare@latestgoflare auth --check: ValidateCLOUDFLARE_API_TOKENfrom environment.goflare build: Build edge function into.build/and static site assets intoweb/public/.goflare deploy: Single path deployment to Cloudflare Workers with assets.⚠️ Designed for CI/CD environments.goflare size: Desglosa el tamaño del wasm del edge por paquete y lista imports prohibidos.goflare tinygo: Instala TinyGo si falta e imprime su directorio bin y su versión.
Deployment is designed to run in CI with a single action line:
- uses: actions/checkout@v4
- uses: webtyp/goflare@v1
with:
worker: mi-worker
domain: mi-worker.ejemplo.cl
d1-binding: DB
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
D1_DATABASE_ID: ${{ secrets.D1_DATABASE_ID }}For more details see CI_GITHUB_ACTIONS.md and CI_D1_SECRETS.md.
edge/main.go (runtime lives in webtyp/cloudflare):
//go:build wasm
package main
import (
"webtyp.com/cloudflare/edge"
"github.com/your-project/routes"
)
func main() {
r := edge.NewRouter(edge.Config{})
routes.Register(r)
edge.Serve(r)
}The edge runtime (
edge,workers,d1,r2,log,cloudflare.Env) is nowwebtyp.com/cloudflare—goflareonly bundles it viacloudflare/assets. Legacywebtyp.com/goflare/edgeis still accepted bymode.goduring migration.
goflare.NewD1Migrator runs DDL migrations against a D1 database from CI —
outside a Worker, where cloudflare/d1.NewEdge doesn't exist. See
docs/D1.md.
Files with //go:build wasm (everything under edge/, routes/, modules/, webtyp/cloudflare) NEVER import fmt, strings, errors, encoding/*, net/http, log, io/ioutil. Use webtyp/fmt, webtyp/json, webtyp/strings, webtyp/fetch instead.
Stdlib inflates the wasm binary ~80%. goflare warns at 256 KiB raw and aborts build at 900 KiB raw to preserve fast cold-start instantiation. 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/ $(go env GOPATH)/pkg/mod/webtyp.com/cloudflare* must return empty — edge runtime lives in webtyp/cloudflare.
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 |
Edge code talks to js.Global(), not to Cloudflare — so it is tested in a browser against a
fake context.env, with no deploy and no wrangler. See docs/TESTING.md
for the three tiers and the rule for choosing one.
gotest # never `go test` — dual WASM/stdlib, browser-driven- Go 1.25.2+
- TinyGo — installed automatically by
goflare buildviawebtyp/tinygo