goflare

package module
v0.5.26 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 33 Imported by: 1

README

GoFlare

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.

When to use

  • 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).

See BUILD_WORKER_ASSETS.md.

Project layout

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 tinywasm/cloudflare/edge or cloudflare/workers
└── .build/                    # generated by goflare
    ├── edge.js                # JS glue bundle
    └── edge.wasm              # compiled edge/main.go

.env

PROJECT_NAME=my-app
# DOMAIN=example.com             # optional custom domain

CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID are secrets — they live in GitHub Secrets, never in .env.

CLI

Install the CLI:

go install github.com/tinywasm/goflare/cmd/goflare@latest
  • goflare auth --check: Validate CLOUDFLARE_API_TOKEN from environment.
  • goflare build: Build edge function into .build/ and static site assets into web/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.

GitHub Setup

Deployment is designed to run in CI with a single action line:

- uses: actions/checkout@v4
- uses: tinywasm/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 function entrypoint

edge/main.go (runtime lives in tinywasm/cloudflare):

//go:build wasm

package main

import (
    "github.com/tinywasm/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 now github.com/tinywasm/cloudflaregoflare only bundles it via cloudflare/assets. Legacy github.com/tinywasm/goflare/edge is still accepted by mode.go during migration.

Migrations from Outside a Worker

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.

⚠️ Critical: NO heavy stdlib in wasm code

Files with //go:build wasm (everything under edge/, routes/, modules/, tinywasm/cloudflare) 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%. 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/github.com/tinywasm/cloudflare* must return empty — edge runtime lives in tinywasm/cloudflare.

Library usage

cfg := &goflare.Config{
    ProjectName: "myapp",
    AccountID:   "acc-id",
}
g := goflare.New(cfg)
g.Build()
g.Deploy()

Config reference

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

Testing

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

Requirements

  • Go 1.25.2+
  • TinyGo — installed automatically by goflare build via tinywasm/tinygo

Documentation

Index

Constants

View Source
const (
	ActionFilePath     = "action.yml"
	ReleaseAssetURLFmt = "https://github.com/tinywasm/goflare/releases/download/%s/%s"
	TinyGoCacheKeyFmt  = "tinygo-${{ runner.os }}-${{ runner.arch }}-%s"
)
View Source
const (
	EnvKeyProjectName       = "PROJECT_NAME"
	EnvKeyAccountID         = "CLOUDFLARE_ACCOUNT_ID"
	EnvKeyWorkerName        = "WORKER_NAME"
	EnvKeyDomain            = "DOMAIN"
	EnvKeyCompilerMode      = "COMPILER_MODE"
	EnvKeyD1DatabaseID      = "D1_DATABASE_ID"
	EnvKeyD1DatabaseName    = "D1_DATABASE_NAME"
	EnvKeyR2BucketID        = "R2_BUCKET_ID"
	EnvKeyR2BucketName      = "R2_BUCKET_NAME"
	EnvKeyCompatibilityDate = "COMPATIBILITY_DATE"
	EnvKeyNotFoundHandling  = "NOT_FOUND_HANDLING"

	DefaultCompatibilityDate = "2026-08-01"
	DefaultNotFoundHandling  = "single-page-application"
	HTMLHandlingDefault      = "auto-trailing-slash"
)
View Source
const (
	ImportEdge    = "github.com/tinywasm/cloudflare/edge"
	ImportWorkers = "github.com/tinywasm/cloudflare/workers"

	// LegacyImportEdge/Workers kept for backwards compat during migration.
	LegacyImportEdge    = "github.com/tinywasm/goflare/edge"
	LegacyImportWorkers = "github.com/tinywasm/goflare/workers"

	ErrNoKnownImport = "cannot infer mode: edge/main.go imports neither " + ImportEdge + " nor " + ImportWorkers
)
View Source
const (
	// WasmWarnSizeKiB is the warning threshold, measured on the RAW size.
	WasmWarnSizeKiB = 256

	// WasmMaxSizeKiB is goflare's OWN budget, not a Cloudflare limit.
	WasmMaxSizeKiB = 900

	// EnvKeyWasmWarnSizeKiB raises or lowers the warning without a rebuild.
	EnvKeyWasmWarnSizeKiB = "WASM_WARN_SIZE_KIB"

	// EnvKeyWasmMaxSizeKiB raises or lowers the hard cut-off without a rebuild.
	EnvKeyWasmMaxSizeKiB = "WASM_MAX_SIZE_KIB"

	// WasmArtifactName is the standard name of the Worker's WASM binary.
	WasmArtifactName = "edge.wasm"
)
View Source
const (
	// TinyGoVersion is the TinyGo version this goflare binary will install.
	TinyGoVersion = tinygo.DefaultVersion

	// TinyGoBinDirPrefix marks the stdout line carrying the directory.
	TinyGoBinDirPrefix = "TINYGO_BINDIR="

	// TinyGoVersionPrefix marks the stdout line carrying the version.
	TinyGoVersionPrefix = "TINYGO_VERSION="
)
View Source
const (
	// CloudflareModulePath is the edge runtime module. goflare embeds its JS
	// assets; the project compiles its Go code. Both halves have to come from
	// the same version.
	CloudflareModulePath = "github.com/tinywasm/cloudflare"
)
View Source
const (
	// CompilerModeStdlib builds the frontend with standard Go instead of TinyGo:
	// large binary, fast build, no minification. This is the development mode.
	CompilerModeStdlib = "L"
)
View Source
const HeaderIdentity = "x-goflare"

HeaderIdentity is the header a goflare-deployed Worker identifies itself with. Its presence proves the response came from the Worker and not from the static file layer.

Variables

View Source
var ErrNotFound = errors.New("not found")
View Source
var WorkerFirstRoutes = []string{"/api/*", "/oauth/*"}

WorkerFirstRoutes are the prefixes Cloudflare must send to the Worker ahead of the static assets. This is not project configuration: /api/ is the route convention of tinywasm/router and /oauth/ is mounted by tinywasm/user. A project using the ecosystem is correct without declaring anything.

Functions

func CheckVersionSkew added in v0.5.23

func CheckVersionSkew(moduleRoot string) error

CheckVersionSkew fails when the project and this binary resolve different versions of tinywasm/cloudflare.

func CheckWasmSize added in v0.5.23

func CheckWasmSize(path string, log func(...any)) error

CheckWasmSize measures the artifact, ALWAYS writes the report to log, warns when it passes the warning threshold, and errors when it passes the budget.

func CompareVersions added in v0.5.23

func CompareVersions(project, embedded string) error

CompareVersions implements the version-skew decision table.

func EmbeddedCloudflareVersion added in v0.5.23

func EmbeddedCloudflareVersion() string

EmbeddedCloudflareVersion returns the github.com/tinywasm/cloudflare version THIS binary was built against.

func EnsureTinyGo added in v0.2.22

func EnsureTinyGo(out io.Writer) error

EnsureTinyGo installs TinyGo if absent and guarantees its bin dir is in PATH before any compilation attempt. Safe to call multiple times (idempotent).

func ExportAssetHash added in v0.5.13

func ExportAssetHash(content []byte, ext string) string

ExportAssetHash exports assetHash for testing.

func FilterActionable added in v0.5.23

func FilterActionable(chains []gobuild.ImportChain) []gobuild.ImportChain

FilterActionable drops the chains where the forbidden package is reached through another stdlib package. Our code neither causes nor can fix those; reporting them only trains the user to ignore the guard.

func ForbiddenImports added in v0.5.23

func ForbiddenImports(moduleRoot, entryPkg string) ([]gobuild.ImportChain, error)

ForbiddenImports returns only the ACTIONABLE chains into forbidden stdlib within the edge graph.

func FormatTinyGoOutput added in v0.5.23

func FormatTinyGoOutput(dir, version string) string

FormatTinyGoOutput produces the standard output of the tinygo command.

func GoflareAction added in v0.5.23

func GoflareAction(tinyGoVersion, goflareVersion string) actiongen.Action

GoflareAction builds the description of the goflare action.

func IsStdlib added in v0.5.23

func IsStdlib(importPath string) bool

IsStdlib reports whether an import path belongs to the Go standard library.

func LatestReleaseTag added in v0.5.23

func LatestReleaseTag() (string, error)

LatestReleaseTag returns the highest semver tag in the repository.

func NewD1Migrator added in v0.5.22

func NewD1Migrator(accountID, databaseID, apiToken string) (ddl.Execer, error)

NewD1Migrator returns a ddl.Execer that runs schema migrations against a D1 database from CI or a developer machine — outside a Worker, where the tinywasm/cloudflare/d1.NewEdge binding does not exist.

It builds on CfClient rather than a second HTTP implementation: Bearer auth and {success,errors,result} envelope parsing are already correct in cloudflare.go's parseCFResponse. This repo is where that belongs — see tinywasm/cloudflare/AGENTS.md, "no tooling code, ever, regardless of build tag".

Usage:

conn, err := goflare.NewD1Migrator(accountID, databaseID, apiToken)
err = ddl.New(conn, sqlt.NewCompiler()).Sync(models...)

func NewD1MigratorFromClient added in v0.5.22

func NewD1MigratorFromClient(client *CfClient, accountID, databaseID string) ddl.Execer

NewD1MigratorFromClient is the test seam: it takes an already-constructed CfClient (whose BaseURL can point at an httptest.Server) instead of building one from real credentials.

func ProjectCloudflareVersion added in v0.5.23

func ProjectCloudflareVersion(moduleRoot string) (string, error)

ProjectCloudflareVersion returns the github.com/tinywasm/cloudflare version the project go.mod in moduleRoot resolves to.

func RunAuth added in v0.2.3

func RunAuth(envPath string, out io.Writer, check bool) error

RunAuth runs the auth command.

func RunBuild added in v0.1.0

func RunBuild(envPath string, out io.Writer) error

RunBuild runs the build command.

func RunDeploy added in v0.1.0

func RunDeploy(envPath string, out io.Writer) error

RunDeploy runs the deploy command.

func RunSize added in v0.5.23

func RunSize(envPath string, out io.Writer) error

RunSize runs the size diagnostic subcommand.

func RunTinyGo added in v0.5.23

func RunTinyGo(out io.Writer) error

RunTinyGo installs TinyGo when missing and prints its bindir and version to stdout.

func SizeBreakdown added in v0.5.23

func SizeBreakdown(entryDir string) (string, error)

SizeBreakdown builds entryDir with symbols and returns the per-package table TinyGo emits. The artifact is written to a temporary directory and deleted: only the report matters. It NEVER replaces the build that gets deployed, which still comes out of sitec without symbols.

func TinyGoBinDir added in v0.5.23

func TinyGoBinDir() (dir, version string, err error)

TinyGoBinDir installs TinyGo when missing and returns the directory holding the binary, along with the version it reports.

func Usage added in v0.1.0

func Usage() string

Usage returns the usage string.

Types

type CfClient added in v0.3.0

type CfClient struct {
	Token      string
	BaseURL    string // default: cfAPIBase; overridden in tests
	HttpClient *http.Client
}

type Config

type Config struct {
	// Project identity
	ProjectName string // PROJECT_NAME
	AccountID   string // CLOUDFLARE_ACCOUNT_ID
	WorkerName  string // WORKER_NAME  (default: ProjectName + "-worker")

	// Routing
	Domain string // DOMAIN (optional — custom domain)

	// Build inputs (conventions, not configurable via .env)
	Entry     string // ENTRY      (path to main Go file, empty = Pages only)
	PublicDir string // PUBLIC_DIR (path to static assets, empty = Worker only)

	// Build output (not in .env — always .build/)
	OutputDir string // default: ".build/"

	// Compiler
	CompilerMode string // "S" | "M" | "L"  default: "S"

	D1DatabaseID   string // D1_DATABASE_ID
	D1DatabaseName string // D1_DATABASE_NAME — optional, default: ProjectName
	R2BucketID     string // R2_BUCKET_ID
	R2BucketName   string // R2_BUCKET_NAME
}

func LoadConfigFromEnv added in v0.1.0

func LoadConfigFromEnv(path string) (*Config, error)

LoadConfigFromEnv reads a .env file and populates Config. Falls back to OS environment variables if .env path is empty or does not exist. Applies defaults after loading.

func (*Config) ValidateBuild added in v0.2.17

func (c *Config) ValidateBuild() error

ValidateBuild checks only what goflare build requires. ProjectName and AccountID are deploy-only — never referenced by build.go.

func (*Config) ValidateDeploy added in v0.2.17

func (c *Config) ValidateDeploy() error

ValidateDeploy checks everything required for a Cloudflare API deploy.

type DeployResult added in v0.1.0

type DeployResult struct {
	Target string
	URL    string
	Err    error
}

DeployResult represents the result of a deployment to a target.

type Goflare

type Goflare struct {
	Config *Config // exported so CLI can read it after LoadConfigFromEnv

	BaseURL string
	SiteURL string // override public URL for testing probe

	RetryBackoff time.Duration // base duration for retries (defaults to 1s)
	// contains filtered or unexported fields
}

func New

func New(cfg *Config) *Goflare

New creates a new Goflare instance with the provided configuration

func (*Goflare) Auth added in v0.0.97

func (g *Goflare) Auth() error

Auth implements token validation.

func (*Goflare) Build added in v0.1.0

func (g *Goflare) Build() error

Build orchestrates the build pipeline.

func (*Goflare) Change

func (h *Goflare) Change(newValue string, progress func(msgs ...any))

func (*Goflare) Deploy added in v0.1.0

func (g *Goflare) Deploy() error

Deploy uploads the site to Cloudflare as a Worker with static assets.

func (*Goflare) ExportBuildAssetManifest added in v0.5.13

func (g *Goflare) ExportBuildAssetManifest(dir string) (map[string]assetEntry, map[string]string, error)

ExportBuildAssetManifest exports buildAssetManifest for testing.

func (*Goflare) ExportUploadAssets added in v0.5.13

func (g *Goflare) ExportUploadAssets(client *CfClient, manifest map[string]assetEntry, byHash map[string]string) (string, error)

ExportUploadAssets exports uploadAssets for testing.

func (*Goflare) GeneratePagesFiles

func (g *Goflare) GeneratePagesFiles() error

func (*Goflare) GenerateWorkerFiles

func (g *Goflare) GenerateWorkerFiles() error

func (*Goflare) Label

func (h *Goflare) Label() string

func (*Goflare) Logger added in v0.0.40

func (g *Goflare) Logger(messages ...any)

func (*Goflare) MainInputFileRelativePath

func (h *Goflare) MainInputFileRelativePath() string

MainInputFileRelativePath returns the relative path to the main input file This is used by devwatch to determine file ownership for Go files

func (*Goflare) Name

func (h *Goflare) Name() string

func (*Goflare) NewFileEvent

func (h *Goflare) NewFileEvent(fileName, extension, filePath, event string) error

NewFileEvent handles file change events for goflare This method is called by devwatch when a relevant file changes

func (*Goflare) SetCompilerMode

func (g *Goflare) SetCompilerMode(newValue string)

SetCompilerMode changes the compiler mode mode: "L" (Large fast/Go), "M" (Medium TinyGo debug), "S" (Small TinyGo production)

func (*Goflare) SetLog added in v0.0.40

func (g *Goflare) SetLog(f func(message ...any))

func (*Goflare) SetSiteBuilder added in v0.5.0

func (g *Goflare) SetSiteBuilder(b SiteBuilder)

SetSiteBuilder sustituye el compilador de sitio. Pensado para tests; en producción nadie lo llama y se usa buildSite.

func (*Goflare) Shortcuts

func (h *Goflare) Shortcuts() []map[string]string

func (*Goflare) StagingDir added in v0.2.13

func (g *Goflare) StagingDir() string

StagingDir returns the temporary directory used for intermediate build artifacts. Exposed for testing — verifies that staging is outside the project tree.

func (*Goflare) SupportedExtensions

func (h *Goflare) SupportedExtensions() []string

SupportedExtensions returns the file extensions that goflare monitors For edge workers, we primarily watch .go files

func (*Goflare) UnobservedFiles

func (h *Goflare) UnobservedFiles() []string

UnobservedFiles returns files that should be ignored by the file watcher These are output files generated by goflare that shouldn't trigger recompilation

func (*Goflare) Value

func (h *Goflare) Value() string

func (*Goflare) WriteSummary added in v0.1.0

func (g *Goflare) WriteSummary(out io.Writer, results []DeployResult)

WriteSummary formats and writes the deploy summary to out.

type MemoryStore added in v0.1.0

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore is an in-memory Store exported for use by library consumers in tests. Safe for concurrent use.

func NewMemoryStore added in v0.1.0

func NewMemoryStore() *MemoryStore

func (*MemoryStore) Get added in v0.1.0

func (s *MemoryStore) Get(key string) (string, error)

func (*MemoryStore) Set added in v0.1.0

func (s *MemoryStore) Set(key, value string) error

type SiteBuilder added in v0.5.0

type SiteBuilder func(cfg sitec.BuildConfig) (SiteOutput, error)

SiteBuilder builds the project's static site.

It is a deliberate seam: the real sitec pipeline demands a valid Go module on disk and an installed compiler, and this repo's tests have neither. The real implementation is buildSite.

type SiteOutput added in v0.5.0

type SiteOutput interface {
	WriteTo(fs sitec.FS) error
}

SiteOutput is the already-built site, ready to be flushed to disk.

type Store added in v0.0.99

type Store interface {
	Get(key string) (string, error)
	Set(key, value string) error
}

Store abstracts access for testability.

type WasmSizes added in v0.5.23

type WasmSizes struct {
	Raw  int64
	Gzip int64
}

WasmSizes holds the two figures that matter for an edge artifact: the raw one, which is what the isolate compiles and instantiates, and the compressed one, which is what Cloudflare weighs against its limit.

func MeasureWasm added in v0.5.23

func MeasureWasm(path string) (WasmSizes, error)

MeasureWasm returns the file's raw size and its gzip-compressed size.

Directories

Path Synopsis
cmd
goflare command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL