Skip to content

ADR-0010: Replace Ocelot with Apache APISIX as the API Gateway

  • Status: ✅ Accepted
  • Date: 2026-03-03
  • Owners: OsmanK

Context

Appcircle currently uses Ocelot as the API Gateway. Ocelot’s primary benefit is that it behaves like a .NET/C# SDK-style gateway, enabling us to implement custom behaviors directly in code (e.g., Keycloak integration, request interception, and producing Kafka events).

As our platform grows, we need an API gateway that is more security-aligned, operationally mature, observable, and performant across SaaS and self-hosted deployments.

Key reasons this change is being discussed:

  1. Complete WAF-aligned security posture We need a gateway architecture that fits a standard “edge security” model where WAF controls and policies can be applied consistently and owned by security operations, without relying on custom per-route code inside the gateway.

  2. Prefer a full-fledged gateway product over an SDK Ocelot encourages embedding gateway responsibilities into application logic. We want a dedicated gateway product that supports core gateway needs via configuration and policies (routing, auth, rate limiting, logging, metrics), reducing long-term maintenance and complexity.

  3. Better performance and scalability management We need stronger control over performance characteristics at the gateway layer: throughput, concurrency, stable behavior under load, and predictable latency.

  4. Strong recommendation from platform stakeholders Osman Çelik and the Keymate team strongly recommend adopting APISIX based on operational experience and believe it better matches our security, performance, and observability requirements.

Note

This ADR does not claim that Ocelot is “bad”. The goal is to align Appcircle’s gateway layer with a more standardized, policy-driven, observable, and security-compatible approach.

Decision

We will replace Ocelot with Apache APISIX as the primary API Gateway for Appcircle.

APISIX will be used to standardize:

  • Authentication and authorization policies (OIDC / Keycloak integration)
  • Traffic management (routing, rate limiting, retries, timeouts)
  • Observability (Prometheus metrics and gateway-level telemetry)
  • Kafka-based signaling/logging (for generic gateway-level events and structured logs)

Warning

We will avoid implementing domain/business workflows inside the gateway. APISIX configuration and plugins are limited to gateway concerns (auth, routing, rate limiting, generic logging/metrics). Domain events remain in services.

Options considered

  • Option A — Keep Ocelot
  • Pros: Maximum C# customization, minimal short-term migration
  • Cons: Security/observability/performance standardization relies on ongoing custom engineering; risk of gateway becoming an application host for cross-cutting logic

  • Option B — Adopt Apache APISIX (Selected)

  • Pros: Dedicated gateway product; policy/plugin-based model; strong observability story; security alignment; better fit for WAF-fronted deployments
  • Cons: Migration effort; some Ocelot custom behaviors must be re-designed as plugins or moved to services

Consequences

  • Positive:
  • Standardized gateway behavior via policies/plugins instead of custom code
  • Improved observability with consistent metrics and operational insight
  • Better security posture alignment via WAF + gateway separation of concerns
  • More predictable performance under load

  • Negative:

  • Migration effort: routes, policies, transformations, operational runbooks
  • Ocelot inline C# behaviors must be mapped to:

    • APISIX plugins for generic capabilities, or
    • a dedicated service when domain-level processing is required
  • Follow-ups / migrations:

  • Run PoC on representative routes (public + authenticated + Kafka-signaling)
  • Define the allowed APISIX plugin set (guardrails)
  • Create runbooks (deploy/upgrade/rollback) and dashboards/alerts
  • Incremental cutover with rollback path until decommissioning Ocelot
  • Related issues/PRs: TBD
  • Impacted components: Ocelot, Keycloak, Kafka, Ingress/WAF layer, Observability stack
  • Supersedes / Superseded by: None