Skip to content

Why v2

HOG v1 was a fork of KrakenD-CE. HOG v2 is a clean-room rewrite: no v1 code is reused — not the fork's packages, not its plugin logic, not the KrakenD-derived core. v2 is built fresh, from the Go 1.26 standard library up, against its own architecture. v1 remains useful only as a reference for requirements and observed behavior (the BFF cookie flow, static serving with auth, trace correlation) — never as a source of code to port.

What changed

A native core, not a framework fork. v1 built on Lura, the KrakenD core framework. For v2 we evaluated Lura, Caddy (as a module host), and building natively on the standard library, and chose native. Recent Go versions moved most of the security-sensitive primitives a gateway needs — traversal-safe static serving (os.Root), a reverse proxy (httputil.ReverseProxy), Fetch-metadata CSRF protection (http.CrossOriginProtection), structured logging (log/slog), container-aware scheduling (GOMAXPROCS) — into the audited standard library. That collapses the cost of owning the request spine yourself, which was the main reason to depend on a framework in the first place.

Kubernetes-style YAML, not KrakenD's config format. Every module is configured by a resource with apiVersion, kind, metadata, and spec — the same shape as a Kubernetes manifest, wired together with label selectors instead of nested configuration blocks. See core concepts for the resource model.

Compile-time Go plugins, not .so files. v1 inherited Lura's runtime plugin model. v2 plugins are Go packages that self-register into a registry at init() and are compiled into the binary alongside the built-ins — full type safety, exact dependency versions, and zero per-request plugin-loading overhead, at the cost of a rebuild to change the plugin set.

Its own middleware chain. v2's request pipeline wraps two gateway-wide edge layers — trusted-proxy normalization (forwarded) and CSRF/security headers (security) — around everything, then a fixed built-in per-route skeleton: recover, request-ID, access log, session, auth gate, authz, projection, with two guarded slots for your code. There is no privileged "core" code path: HOG's own features (static serving, proxying, aggregation, authentication, authorization, observability) are built on the same module contract a third-party plugin uses.

Design ethos

A few decisions repeat across every v2 subsystem:

  • Standard-library-first. External dependencies are kept deliberately small: an OpenID Connect (OIDC) client, a JWT library, an embedded Open Policy Agent (OPA) engine, a Valkey client for optional shared state, and a YAML parser. Where the standard library can do the job, v2 uses it.
  • Secure by default. Static serving is traversal-resistant by construction. Refresh tokens never reach the browser, encrypted or not. Authorization fails closed: a policy evaluation error denies the request rather than allowing it.
  • Fail-closed, fail-fast. Bad configuration is a boot-time error, not a runtime surprise. A denied policy, an expired session, or a panic all resolve to a safe response, never a silent pass-through.
  • One binary. Built-in modules and your plugins compile into a single static artifact — no sidecars, no runtime dependencies, no external control plane. Any number of replicas with identical config behave as one coordination-free cluster.

Where to go next

If you're running HOG v1 today, start with migrating from v1 — it maps v1 configuration and behavior onto v2's equivalents. If you want the reasoning behind a specific subsystem — why sessions are cookie-based, why authorization is hard-wired to OPA, why plugins are compile-time only — read design choices. Otherwise, continue to core concepts or jump straight to the quick start.