Records the move from Scala to Go, the compiled-plugin decision, the Płytarium port as the v1 target, and the Go ecosystem research that backs the choice. No code yet.
70 lines
7.2 KiB
Markdown
70 lines
7.2 KiB
Markdown
---
|
|
title: Go ecosystem viability for SummerCMS
|
|
date: 2026-09-16
|
|
source: Research pass during the opening exploration session. Stars and last-push dates verified via GitHub API on 2026-09-16 unless tagged [ASSUMED].
|
|
---
|
|
|
|
# Go ecosystem viability report (WinterCMS -> Go)
|
|
|
|
Verdict: the "Go is closer to PHP's richness" bet holds for every concern except the plugin model, and that has a proven answer (section 2).
|
|
|
|
## 1. Ecosystem coverage
|
|
|
|
| Concern | Pick (stars, last push) | Runner-up | Maturity note |
|
|
|---|---|---|---|
|
|
| HTTP router | net/http ServeMux (stdlib; method and wildcard patterns since 1.22) | chi 22.8k (09-2026) | stdlib mux is enough for a CMS; chi adds middleware groups and stays net/http-compatible. gin 89k, echo 32.7k, fiber 40k are alive but use non-stdlib handler types; fiber (fasthttp) breaks stdlib middleware. Avoid. |
|
|
| ORM / query | ent 17.2k (09-2026) or GORM 40k (09-2026) | bun 5k, sqlc 18.3k | ent = schema-as-code + codegen, best fit for YAML-driven form generation and migrations. GORM = closest to Eloquent DX, weaker typing. sqlx 17.7k last push 2024-08, stagnant. |
|
|
| Migrations | goose 11.5k (09-2026) | golang-migrate 18.9k, atlas 8.7k | goose supports Go-code migrations (needed for plugin migrations). atlas pairs with ent for declarative diff. |
|
|
| OAuth2 / OIDC server | zitadel/oidc 1.9k (09-2026), OP+RP, OpenID-certified | go-oauth2/oauth2 3.6k (09-2026, RFC 6749 only, no OIDC) | This is the Scala gap, closed. ory/fosite 2.6k last push 2025-11; Ory pushes users to Hydra. Reference only. |
|
|
| JWT | golang-jwt/jwt 9.2k (09-2026) | | De facto standard. |
|
|
| Sessions | alexedwards/scs 2.6k (11-2025) | gorilla/sessions 3.2k (08-2024) | scs is server-side with pluggable stores (pg, redis, sqlite). gorilla is cookie-signed and dormant. |
|
|
| Validation | go-playground/validator 20.2k (09-2026) | | Tag-based, i18n error messages, maps well to YAML `rules:`. |
|
|
| Config | koanf 4.2k (09-2026) | viper 30.5k (01-2026) | koanf is lighter with fewer deps. Either fine. |
|
|
| CLI | cobra 44.6k (07-2026) | urfave/cli 24.2k (09-2026) | cobra for `summer make:plugin`-style scaffolding. |
|
|
| Templates | html/template (stdlib) + templ 10.5k (09-2026) for typed components | pongo2 3.1k (05-2026) for Twig syntax | pongo2 gives theme authors Twig-like syntax (WinterCMS parity) but is single-maintainer. Use it only for themes, not admin. |
|
|
| i18n | go-i18n 3.5k (09-2026) | spreak 94 stars | go-i18n is CLDR-plural, standard. |
|
|
| Queue / jobs | river 5.7k (09-2026, Postgres/SQLite, transactional) | asynq 13.7k (06-2026, Redis) | river avoids a Redis dependency. |
|
|
| Cache | otter 2.7k (06-2026) in-memory; go-redis 22.2k (09-2026) | ristretto 7k (09-2026) | otter v2 is W-TinyLFU, faster than ristretto per maintainers' benchmarks [ASSUMED]. |
|
|
| Mail | wneessen/go-mail 1.5k (09-2026) | | Active, SMTP auth variants, no deps. |
|
|
| Events / pubsub | In-process: hand-rolled typed bus with generics | watermill ~8k [ASSUMED] for cross-process | No dominant in-process event lib. It is ~200 LOC. |
|
|
| WebSockets | coder/websocket 5.5k (06-2026) | gorilla/websocket 24.9k (03-2025) | coder is context-aware and wasm-capable. gorilla maintained but quiet. |
|
|
| File storage | gocloud.dev/blob 9.9k (09-2026) | afero 6.7k (09-2026) | blob = S3/GCS/Azure/local behind one API (Flysystem equivalent). afero for FS mocking. |
|
|
|
|
## 2. Plugin architecture (key risk)
|
|
|
|
| Approach | Real project | DX | Verdict |
|
|
|---|---|---|---|
|
|
| (a) Compile-time registration + custom build | Caddy + xcaddy 1.5k (08-2026); Grafana core; Hugo | Plugin = Go module with `init()` registering into a registry. `summer build --with github.com/x/plugin` rebuilds the binary. | Recommended. Full type safety, zero runtime overhead, plugins extend each other via normal Go interfaces, `go test` works. Pain: rebuild required (seconds), Go toolchain at deploy or in CI. |
|
|
| (b) stdlib `plugin` | almost nobody in prod | Linux/macOS only, host and plugin must share exact toolchain and dep versions, no unload, panic kills host | Reject. Docs still say "known to have a number of issues". |
|
|
| (c) RPC subprocess | hashicorp/go-plugin 6.1k (09-2026); Grafana backend plugins; Terraform | Each plugin a separate binary over gRPC, 30-50us per call | Good for isolation, wrong for a CMS where plugins register models, form fields, components, and extend each other. Surface too wide to marshal. |
|
|
| (d) WASM | extism 5.8k (09-2026) on wazero (~5k [ASSUMED]) | Sandboxed, polyglot, hot-reloadable | Same interface-width problem as (c), plus no direct DB/ORM access from guest. Suitable only for untrusted marketplace "widgets". |
|
|
| (e) Interpreter | traefik/yaegi 8.4k, last push 02-2026, README targets Go 1.21/1.22 | Drop source in folder, runs at startup. Traefik vendors deps because yaegi has no module support. | Lagging Go releases badly, partial generics, no cgo, slower. Traefik plugins are tiny middlewares, not CMS plugins. |
|
|
|
|
Recommendation: (a) as the primary mechanism, mirroring xcaddy: `plugins/` dir of Go modules, a generated `plugins.go` import list, `summer plugin:add` / `make:plugin` commands that scaffold, rewrite go.mod (replace directive for local dev) and rebuild. Add an `air`/reflex-style watch-rebuild for dev to feel like WinterCMS's drop-in loop. Keep an optional (d) WASM slot later for untrusted extensions. This is what Hugo, Caddy, Grafana core, Mattermost (partly), and Gitea converged on.
|
|
|
|
## 3. Existing Go frameworks and CMSes
|
|
|
|
| Project | Status | Steal | Base or reference |
|
|
|---|---|---|---|
|
|
| Goravel (framework 524 stars, skeleton 4.8k, 09-2026) | Alive, active issues 2026 | Facade layer, artisan-style CLI, Laravel-shaped config/queue/mail abstractions | Reference only. Small core team, own ORM wrapper, coupled to its facades. |
|
|
| GoFrame 13.3k (09-2026) | Alive, Chinese-led | `gf gen` codegen (dao/model/ctrl), gi18n, config, ORM | Reference. Monolithic, non-idiomatic. |
|
|
| Beego 32.4k (09-2026) | Alive but legacy | Little; MVC only | Reference. |
|
|
| Buffalo 8.4k | Archived Feb 2024; API shows unarchived, push 03-2026 (unclear) | `pop` ORM migrations, plush templates, generators | Dead for basing. |
|
|
| PocketBase 61k (09-2026) | Very alive; "standalone app or Go framework"; SQLite; hooks + JS VM (goja) plugin | Hook/event system, collection-schema-driven admin UI, Go-framework-mode API | Best reference for schema-driven admin forms. Not a base (SQLite-only, no plugin packaging, single maintainer). |
|
|
| Fastschema 571 (07-2026) | Beta | ent-backed schema-to-CRUD, plugin system | Reference. Too small. |
|
|
| Ponzu 5.8k | Abandoned (README says so) | Nothing | Dead. |
|
|
|
|
## 4. Go 1.27 (Aug 2026) notes
|
|
|
|
- Generic methods landed (methods may declare their own type params, not on interfaces). Cleans up repository and query-builder APIs.
|
|
- `encoding/json` now backed by json/v2: faster, stricter (rejects duplicate keys and invalid UTF-8). Relevant to YAML/JSON form definitions.
|
|
- Iterators (`range over func`, `iter` pkg) stable since 1.23. Use for paginated model queries.
|
|
- net/http ServeMux method and wildcard patterns stable since 1.22. 1.27 adds RFC 9218 HTTP/2 priority.
|
|
- No change to `plugin` package limitations.
|
|
|
|
## Flags
|
|
|
|
- wazero star count unverified.
|
|
- Buffalo archived-status contradiction (web says archived 2024, API says not).
|
|
- otter-vs-ristretto performance claim is from maintainer benchmarks, not independently verified.
|