Skip to main content

Choosing a Kong alternative: a plugin-by-plugin migration map for regulated teams

Looking for a Kong alternative? Map every Kong service, consumer and plugin to a self-hosted gateway with built-in audit, AI agent access and flat pricing.

  • comparisons
  • migration
  • enterprise
  • architecture
  • compliance
Zerq team

Most teams evaluating a Kong alternative are not unhappy with Kong's proxy. Kong Gateway is fast, its plugin model is flexible, and plenty of platform teams have run it in production for years. What pushes the evaluation is the product around the proxy. Kong's own install documentation still lists 3.9.x as the latest open-source release, community threads report that prebuilt OSS images stopped with the 3.10 line, and new capability (the AI Gateway, MCP governance, the Konnect MCP Registry) is arriving in Konnect, Kong's SaaS control plane, rather than in the gateway you self-host.

For a bank, a payer, or a government team, that turns a version upgrade into an architecture decision. Staying current means one of three things: build OSS images from source and own the patching, buy Kong Enterprise and license the plugins you already depend on, or move the control plane into Konnect and add a vendor cloud to your outsourcing register. If you are going to re-examine the estate anyway, it is reasonable to ask what the estate should run on.

This is the engineering version of that question. It maps a Kong estate (services, routes, consumers, credentials, and the plugins attached to them) to the equivalent constructs in Zerq, shows what each migrated piece looks like in configuration, and gives a sequence that moves traffic without a freeze. The short comparison is at zerq.dev/compare/zerq-vs-kong.

Why Kong estates get harder to run in regulated environments

Kong's design is a small core plus plugins. Authentication, rate limiting, logging, transformation, and caching are all plugins, configured per service, per route, per consumer, or globally. That is a clean model on day one. By year three, the behaviour of a single route is the sum of plugins configured at four scopes, some of them open source, some Enterprise-only (openid-connect, mtls-auth, rate-limiting-advanced), and some custom Lua that one engineer wrote. An auditor asking "what controls apply to this partner on this endpoint" gets an answer assembled from the Admin API, a decK file, and someone's memory of plugin precedence.

The audit story fragments in the same way. Kong's Admin API audit logging is an Enterprise feature. Request logging is a plugin (http-log, file-log, tcp-log) that ships records to a sink you operate, so request evidence lives in Elasticsearch or a SIEM while configuration lives in Postgres or a declarative file. Metrics are another plugin. The developer portal is in Konnect. That is five places to look when a regulator asks for one answer.

The third pressure is AI traffic. Kong's AI and MCP work is real, but it is concentrated in AI Gateway plugins and Konnect features. For a self-hosted team, putting agents in front of internal APIs means either adopting that cloud control plane or running agent traffic through a second path with its own credentials and its own logs. That is the two-gateway problem regulated teams are trying to avoid.

What a Kong alternative has to replace

Zerq's architecture is a single Go binary that serves gateway traffic, the management API, and both MCP endpoints, with a Next.js management UI and developer portal alongside it. Configuration, request logs, and the management audit trail all live in your own MongoDB. Redis is optional and only shares cache and rate limit state across replicas. There is no external control plane and the same deployment runs fully offline.

The important difference from Kong is that most of what Kong does in plugins, Zerq does in the access model itself. The concept map:

Kong constructZerq equivalentNotes
ServiceCollectionendpoint is the upstream, base_path is the public prefix
RouteProxy inside a collectionpath, methods, target_path
ConsumerClientThe business identity that appears in every log entry
key-auth credentialProfile with token authToken generated once, rotatable with expiry
jwt pluginProfile with jwt authSignature checked with a client/profile-scoped secret
openid-connect (Enterprise)Profile with oidc authValidated against your issuer's JWKS
mtls-auth (Enterprise)Profile with mtls authCertificate checked at ingress, profile rules enforced after
aclCollections assigned to the clientA client can only reach its collections
ip-restrictionProfile allowedIPsExact IPs or CIDR, checked before auth
Method limits via pluginsProfile allowedMethodsOther methods return 405
rate-limiting, rate-limiting-advancedPolicy attached to the clientRate limit plus long-window quota
request-transformerProxy headers, set_nodeStatic or env-var headers; body shaping in workflows
request-validatorvalidate_nodeJSON Schema check, branches on valid/invalid
pre-function, custom Luacode_nodeJavaScript in config.code
proxy-cacheGateway response cacheKeyed per client and profile
http-log, file-logRequest logs in MongoDBNo log shipper to run
decKCollection JSON export/import, Management MCPPromote config between environments

Two planning notes. Zerq policies apply per client across all of that client's profiles, so a Kong setup with different rate limits per route for the same consumer becomes separate clients or a workflow-level control. And Zerq validates tokens from your IdP rather than issuing them, so Kong's oauth2 plugin acting as an authorization server moves to your IdP, which is usually where regulated teams want it.

Authentication and access: from plugins to profiles

In Kong, a consumer gets a credential and a set of plugins decides what it may do. In Zerq, every consumer is a client, and every client has one or more profiles. A profile fixes the auth type (token, jwt, oidc, mtls, or none), optional IP restrictions, and optional allowed methods. The full model is in the security overview.

The order of checks is fixed, which is what makes it auditable. On every request the gateway parses X-Client-ID and X-Profile-ID, confirms the client and profile are active and belong together, validates the credential, checks the source IP against allowedIPs, checks the method against allowedMethods, confirms the path belongs to one of the client's collections, and finally applies the rate limit and quota. Only then does the request reach the proxy or its workflow. None of these checks are plugins, so there is no precedence to reason about.

A migrated Kong consumer that used key-auth, ip-restriction, and a GET-only rule looks like this as a profile, using the field names from the profile model:

{
  "name": "production",
  "active": true,
  "authType": "token",              // was key-auth; token is generated once and shown once
  "allowedIPs": ["203.0.113.0/24"], // was ip-restriction; empty list allows all IPs
  "allowedMethods": ["GET"]         // was a method rule; any other method returns 405
}

Kong's openid-connect plugin maps to an oidc profile validated against your issuer's JWKS. For mTLS, note the boundary: Zerq expects certificate validation at the ingress or load balancer, then enforces the profile, IP, method, and policy checks.

Rate limiting: from per-route plugins to client policies

Kong's rate-limiting plugin can attach at any scope with second, minute, hour, day, month, or year windows. Zerq separates the two jobs. A policy defines a short-window rate limit and a long-window quota, attached to the client:

{
  "name": "Partner gold tier",
  "description": "Replaces Kong rate-limiting minute=1200, month=2000000 on consumer group 'gold'",
  "active": true,
  "rate_limit_interval": "1m",   // 1m, 5m, or 1h
  "rate_limit_requests": 1200,   // across all of the client's profiles combined
  "quota_interval": "30d",       // 1d, 7d, or 30d; 30d resets on the 1st of the month (UTC)
  "quota_requests": 2000000      // exceeding it returns 429 with a Retry-After header
}

With multiple gateway replicas, set CACHE_TYPE=redis so counters are shared; a single replica runs with CACHE_TYPE=memory and no Redis at all.

Transformation, validation, and custom Lua: from plugins to workflows

Routes that only authenticate, limit, and forward need no workflow in Zerq. Header injection that Kong did with request-transformer is a proxy setting: each header is either static or read from a named environment variable at runtime, so an upstream API key injected from Vault never lands in the database.

The routes that carried real logic in pre-function, request-validator, or custom Lua move to the workflow builder, a visual pipeline of nodes attached to a proxy. A validate_node checks the body against a JSON Schema, a proxy_node forwards to the backend, an http_request_node calls a second service with timeout_ms and retry_config, a set_node shapes the output, and a response_node returns an explicit status and body. Custom logic that genuinely needs code goes in a code_node:

{
  "id": "risk_flag",
  "type": "code_node",
  "config": {
    "code": "const amt = $json['http_trigger'].request.body.amount; return { review: amt > 10000 };"
  }
}

Unlike custom Lua, the workflow is visible on a canvas, every save is versioned and audited, and nobody rebuilds it against a new gateway release.

Caching: from proxy-cache to the gateway cache

Kong's proxy-cache plugin maps to the gateway's built-in response cache, controlled through environment variables rather than per-route plugin config:

# backend environment: gateway response cache
GATEWAY_ENABLE_CACHE=true        # turn on response caching for gateway routes
GATEWAY_CACHE_TTL=60s            # entry lifetime; defaults to 1m when unset
GATEWAY_CACHE_MAX_BYTES=10485760 # memory ceiling; defaults to 10MB
CACHE_TYPE=redis                 # share cache entries across replicas
REDIS_URL=redis.internal:6379    # only read when CACHE_TYPE=redis

The cache key includes X-Client-ID, X-Profile-ID, client IP, path, and query string, so one partner's cached response is never served to another. Streaming proxies skip the cache automatically.

Logging and audit: from log plugins to one MongoDB

This is where regulated teams feel the difference most. There is no http-log to configure and no shipper to keep alive. Every gateway request writes a request log entry to your MongoDB:

{
  "method": "GET",
  "path": "/accounts/v1/balances",
  "target_url": "https://core-accounts.internal/v1/balances",
  "status": 200,
  "latency": 41,                                         // milliseconds, end to end
  "client_ip": "203.0.113.24",
  "client_id": "66f1c2a9e4b0a1d2c3f40011",               // replaces the Kong consumer
  "profile_id": "66f1c2a9e4b0a1d2c3f40012",              // which credential and rule set was used
  "collection": "Accounts",                              // replaces the Kong service
  "request_id": "0c6a7e19-3f52-4d0b-8b1e-6a2f9c4d7e30",  // also returned as X-Request-ID
  "created_at": "2026-10-15T08:02:11Z"
}

Entries also carry request and response headers and bodies, plus an error field on failures, so a 403 or 429 is evidence with the caller's identity attached, not a missing line. Configuration changes go to a separate audit log with actor_id, actor_type, resource_type, action, ip_address, and user_agent, without an Enterprise licence. A compliance officer with the auditor role reads both through the observability views, filtering by client, profile, path, status class, latency, and time range, with no permission to change configuration.

Config as code: from decK to export, import, and Management MCP

Teams that run decK in CI keep the habit. Collections export as JSON and import in Merge or Replace mode, with imported proxies landing in draft until published. For finer-grained automation, Management MCP exposes the catalog through tools such as list_collections, create_proxy, create_policy, create_profile, and list_audit_logs, using the same OIDC session and role checks as the management UI.

AI agents: the second gateway you do not need

Agents connect to Gateway MCP on the same binary, authenticate as a client profile like any partner, and get four tools: list_collections, list_endpoints, endpoint_details, and execute_endpoint. They discover only the collections their client is assigned, and every execute_endpoint call passes the same profile checks and policy, then writes the same request log entry shown above. Governing agents is a new client, not a parallel stack.

Running the migration

Move one Kong service at a time. A sequence that works:

  1. Run deck gateway dump (or export from the Admin API) to get a full inventory of services, routes, consumers, and plugins. Tag every plugin as "gateway does this natively" (auth, ACL, IP, rate limit, cache, logging) or "needs a workflow" (transformation, validation, Lua).
  2. Export or generate an OpenAPI 3.x spec for each service. In the Zerq management UI, open Collections, choose Import from OpenAPI, upload the file, review the preview, and import. Zerq creates the collection and one draft proxy per path and method.
  3. Set the collection's target endpoint and attach backend credentials, using environment-variable-backed values for anything Kong held in plugin config or a vault reference.
  4. Under Policies, click New Policy for each Kong rate limit tier and translate the windows into rate_limit_* and quota_* fields.
  5. Under Clients, click New Client for each Kong consumer, assign the collections that matched its ACL groups, and attach the policy. Inside the client, create a profile per environment with the auth type, allowed methods, and CIDR ranges from the old plugins. Copy the X-Client-ID and X-Profile-ID values for the partner.
  6. Rebuild the "needs a workflow" routes on the canvas and test each with a listen-for-request run.
  7. Prove one allow path and each deny path per client with curl: 200 for an authorized call, 405 for a blocked method, 403 for an out-of-range IP or a collection outside the client's access, 429 past the limit. Each should appear in the request logs with the client's identity.
  8. Publish, run both gateways in parallel, compare Zerq request logs with your Kong log sink for the same traffic, then shift traffic at the load balancer and keep Kong available for rollback until the logs show nothing left on it.

Plan to issue new credentials rather than carry Kong keys across. The portal makes that cheap: enable developer portal access on the client, add the partner's authorized emails, and they sign in by magic link to copy their new headers and try their endpoints.

A checklist before you decide

Put these questions to every option, including staying on Kong:

  • Which of your active plugins are Enterprise-only, and what does the next renewal cost if you keep them?
  • If Konnect or any vendor cloud were unreachable for a week, could you still change config, onboard a partner, and read your own logs?
  • For one partner on one route, can you produce every control that applied without reading plugin precedence rules?
  • How much custom Lua do you own, and who rebuilds it on the next major release?
  • When AI agents need API access, do they share the same credentials, limits, and audit trail as partners, and is that included in the base licence?

What this looks like in practice

Illustrative scenario, not a specific customer deployment.

A payments processor runs Kong OSS 3.9 on Kubernetes in DB-less mode with decK in CI: about forty services, three hundred routes, and ninety consumers. Around it: key-auth and jwt for partners, a homegrown OIDC Lua plugin, Redis-backed rate-limiting, http-log into Elasticsearch, and a static partner docs site. The 3.10 upgrade surfaces the image question at the same time as a PCI DSS assessment asks for per-partner evidence of denied requests, which Elasticsearch has but cannot tie cleanly to configuration history.

The team deploys Zerq against its existing MongoDB and Keycloak. Routing-only services move first by OpenAPI import. Consumers become clients with sandbox and production profiles; the homegrown OIDC plugin is replaced by oidc profiles; the four rate limit tiers become four policies. Eleven routes with Lua become workflows, nine of them a validate_node plus a set_node, two with a code_node. The Elasticsearch log path and the docs site are retired. The assessor gets the auditor role and a saved request log filter instead of a CSV export, and the first internal AI agent goes live as one more client scoped to the sandbox collection.

What you end up with

A Kong alternative for a regulated team is less about a faster proxy and more about collapsing the plugin estate into a model you can explain. Authentication, ACLs, IP and method rules, and rate limits become fixed checks on clients and profiles instead of plugins at four scopes. Custom Lua becomes versioned, audited workflows on a canvas. Request logs and the config audit trail land in your own MongoDB without a shipper or an Enterprise tier. Partners and AI agents share one access model, one portal, and one audit trail. The control plane stays inside your boundary, and the licence is a flat annual fee per environment.


Zerq is an enterprise API gateway built for regulated industries — one platform for API management, AI agent access, compliance audit, and developer portal, running entirely in your own infrastructure. See how it works or request a demo to walk through your specific requirements.