Zuplo
API Gateway

Migrating from Kong to Zuplo: Plugin Mapping, Architecture Translation, and Step-by-Step Guide

Nate TottenNate Totten
March 20, 2026
11 min read

A practical guide for teams migrating from Kong Gateway to Zuplo, covering plugin-to-policy mapping, config translation, and a phased migration plan.

Kong Gateway has served many teams well, but as API programs grow, the operational overhead of managing NGINX-based infrastructure, Lua plugins, and PostgreSQL or Cassandra databases becomes a real burden. If your team is evaluating a move to a managed, edge-native API gateway, this guide walks you through every step of migrating from Kong to Zuplo.

Table of Contents

  1. Why Teams Migrate from Kong
  2. Architecture Comparison
  3. Plugin-to-Policy Mapping
  4. Translating Kong Configuration to Zuplo
  5. Authentication Migration
  6. Rate Limiting Migration
  7. Custom Plugin Migration
  8. Developer Portal Migration
  9. CI/CD and GitOps
  10. Migration Checklist and Timeline
  11. Frequently Asked Questions
  12. Next Steps

Why Teams Migrate from Kong

Kong is a capable API gateway, but several pain points drive teams to look for alternatives:

  • Operational complexity — Self-hosted Kong requires provisioning and maintaining PostgreSQL or Cassandra, configuring clustering, and managing NGINX tuning. Even Kong Konnect (the managed offering) still requires you to run your own data plane nodes.
  • Upgrade burden — Major Kong version upgrades (e.g., 3.x to 4.x) involve database migrations, plugin compatibility checks, and multi-node rollout coordination. Teams often defer upgrades for months because the risk is too high.
  • Plugin maintenance — Kong’s Lua-based plugin ecosystem is powerful but niche. Finding developers fluent in Lua is difficult, and debugging Lua plugins running inside NGINX worker processes is painful compared to modern tooling.
  • Declarative config drift — While Kong’s decK tool brings declarative configuration, it sits outside Kong’s core runtime. Teams frequently encounter drift between their decK files and the actual Admin API state, especially in environments with mixed declarative and imperative management.
  • Cost at scale — Kong Enterprise licensing is per-node and can escalate quickly in multi-region or high-availability deployments.

Architecture Comparison

Understanding the architectural differences helps you plan a clean migration.

Kong’s Architecture

Kong is built on NGINX and uses Lua (via the LuaJIT runtime) for plugin execution. A typical deployment involves:

  • A control plane that manages configuration (Admin API + database)
  • One or more data plane nodes that proxy traffic (NGINX workers)
  • A PostgreSQL or Cassandra database for storing routes, services, plugins, and consumers
  • Optional decK CLI for declarative config management
  • Plugins written in Lua (or Go/Python via external process execution)

Zuplo’s Architecture

Zuplo takes a fundamentally different approach:

  • Edge-native deployment — Your gateway runs across 300+ data centers worldwide automatically. There is no single-region deployment to manage or scale.
  • OpenAPI-native routing — Routes are defined in a standard routes.oas.json file using the OpenAPI specification format, extended with x-zuplo-route for gateway behavior.
  • TypeScript policies — Instead of Lua plugins, you write policies in TypeScript with full IDE support, type safety, and access to npm packages.
  • Git-native CI/CD — Every configuration change is version-controlled. Push to GitHub, and your gateway deploys to the edge automatically.
  • Fully managed — No databases, no clustering, no NGINX tuning. Zuplo handles all infrastructure, scaling, and updates.
  • Built-in developer portal — Auto-generated from your OpenAPI spec, with API key management and API explorer included.

Plugin-to-Policy Mapping

One of the biggest questions during migration is: “What replaces my Kong plugins?” Below is a mapping of Kong’s most popular plugins to their Zuplo equivalents.

Authentication

  • key-authAPI Key Authentication — Zuplo’s built-in API key policy includes a managed key service with self-service key management through the developer portal.
  • jwtJWT Auth Policy (OpenID) — Validates JWT tokens from any OpenID-compliant provider. Works with Auth0, Okta, Azure AD, and others out of the box.
  • basic-authBasic Auth Policy — Built-in support for HTTP Basic authentication.
  • oauth2JWT Auth Policy — Zuplo validates OAuth2 bearer tokens as JWTs. For OAuth2 token issuance, you continue to use your identity provider (Auth0, Okta, etc.) and Zuplo validates the resulting tokens.
  • ldap-authLDAP Auth Policy — Direct LDAP authentication support.
  • mtls-authmTLS Auth Policy — Mutual TLS authentication for service-to-service communication.

Traffic Control

  • rate-limitingRate Limiting Policy — Supports per-user, per-IP, per-API-key, or custom attribute-based rate limits. No Redis or separate database needed for basic usage.
  • request-size-limitingRequest Size Limit Policy — Built-in policy to enforce a maximum request body size in bytes.
  • ip-restrictionIP Restriction Policy — Allow/deny lists with CIDR range support using a custom policy template. You can also write your own IP filtering logic using the Custom Code Inbound Policy.
  • corsCustom CORS Policy — Configure allowed origins, methods, and headers per route. Supports wildcard subdomains and environment variables.

Request/Response Transformation

Security

  • aclRBAC Authorization Policy — Role-based access control using claims from authenticated users. This is a custom policy template that you can adapt to your specific authorization requirements.
  • bot-detectionBot Detection Policy (enterprise) — Bot scoring and detection for identifying automated traffic. For cryptographic bot identity verification (such as verifying Googlebot), see the Web Bot Auth Policy.

Observability

  • prometheus / datadog / file-log → Zuplo includes built-in observability with log tailing in the portal and integrations with popular log aggregation services like Datadog. See the Zuplo documentation for details on logging integrations.

Validation

  • request-validatorRequest Validation Policy — Validates request bodies, query parameters, path parameters, and headers against your OpenAPI schema definitions automatically.

Now that you understand the architectural differences and how Kong concepts map to Zuplo, let’s walk through each area of your migration.

Translating Kong Configuration to Zuplo

Kong Declarative Config → Zuplo Routes

In Kong, you define services and routes in kong.yml (or manage them via the Admin API / decK):

YAMLyaml
# kong.yml
_format_version: "3.0"
services:
  - name: user-service
    url: http://internal-api.example.com:8080
    routes:
      - name: get-users
        paths:
          - /api/users
        methods:
          - GET
    plugins:
      - name: rate-limiting
        config:
          minute: 60
          policy: local
      - name: key-auth
        config:
          key_names:
            - apikey

In Zuplo, the equivalent lives in routes.oas.json — a standard OpenAPI file extended with Zuplo-specific configuration:

JSONjson
{
  "paths": {
    "/api/users": {
      "get": {
        "summary": "Get Users",
        "x-zuplo-route": {
          "corsPolicy": "none",
          "handler": {
            "export": "urlRewriteHandler",
            "module": "$import(@zuplo/runtime)",
            "options": {
              "rewritePattern": "http://internal-api.example.com:8080/api/users"
            }
          },
          "policies": {
            "inbound": ["api-key-auth", "rate-limit"]
          }
        }
      }
    }
  }
}

The corresponding policies are defined in policies.json:

JSONjson
{
  "policies": [
    {
      "name": "api-key-auth",
      "policyType": "api-key-inbound",
      "handler": {
        "export": "ApiKeyInboundPolicy",
        "module": "$import(@zuplo/runtime)"
      }
    },
    {
      "name": "rate-limit",
      "policyType": "rate-limit-inbound",
      "handler": {
        "export": "RateLimitInboundPolicy",
        "module": "$import(@zuplo/runtime)",
        "options": {
          "rateLimitBy": "ip",
          "requestsAllowed": 60,
          "timeWindowMinutes": 1
        }
      }
    }
  ]
}

Key differences to note:

  • OpenAPI-native — Zuplo routes are standard OpenAPI paths. You can import an existing OpenAPI spec and add x-zuplo-route extensions.
  • Policies replace plugins — Instead of attaching plugins to services or routes via the Admin API, you reference named policies in your route config.
  • Everything in Git — Both routes.oas.json and policies.json are files in your repository. There is no separate database or Admin API to manage.

Authentication Migration

Authentication is typically the most critical part of any gateway migration. Here is how to approach each Kong auth plugin.

API Key Authentication

Kong’s key-auth plugin stores API keys in its database and validates them on each request. Zuplo’s API Key Authentication policy provides a managed API key service where you can:

  1. Create consumers with metadata (plan tier, organization, etc.)
  2. Issue API keys that are automatically validated at the edge
  3. Let developers self-manage their keys through the developer portal
  4. Access consumer metadata in your policies via request.user

To migrate, export your Kong consumers and their API keys, then create corresponding consumers in Zuplo’s API key service using the API Key Management API.

JWT Authentication

Kong’s jwt plugin validates JWT tokens against stored consumer credentials. Zuplo’s JWT Auth Policy validates tokens against any OpenID-compliant identity provider using JWKS (JSON Web Key Sets).

If you are using Kong to validate JWTs from an identity provider like Auth0 or Okta, migration is straightforward — configure Zuplo’s JWT policy with the same issuer and audience values:

JSONjson
{
  "name": "jwt-auth",
  "policyType": "open-id-jwt-auth-inbound",
  "handler": {
    "export": "OpenIdJwtInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "issuer": "https://your-tenant.auth0.com/",
      "audience": "https://api.example.com/",
      "jwkUrl": "https://your-tenant.auth0.com/.well-known/jwks.json"
    }
  }
}

Rate Limiting Migration

Kong offers both rate-limiting (open source) and rate-limiting-advanced (enterprise) plugins with local, cluster, and Redis-backed strategies.

Zuplo’s Rate Limiting policy provides:

  • Per-user, per-IP, or per-key limiting — Choose what attribute to rate limit by.
  • Custom bucket functions — Write a TypeScript function to define custom rate limit grouping logic (e.g., rate limit by customer tier).
  • No external dependencies — Unlike Kong’s Redis-backed strategy, Zuplo’s rate limiter works out of the box without managing additional infrastructure.
  • Standard 429 responses — Automatically returns 429 Too Many Requests with appropriate Retry-After headers.

A typical rate limit configuration in Zuplo:

JSONjson
{
  "name": "rate-limit",
  "policyType": "rate-limit-inbound",
  "handler": {
    "export": "RateLimitInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "rateLimitBy": "user",
      "requestsAllowed": 100,
      "timeWindowMinutes": 1
    }
  }
}

Custom Plugin Migration

If your team has built custom Kong plugins in Lua (or Go), migrating them to Zuplo TypeScript policies is usually simpler than you might expect. Zuplo’s Custom Code Inbound Policy lets you write arbitrary request processing logic in TypeScript.

Kong Lua Plugin vs. Zuplo TypeScript Policy

Here is a side-by-side comparison of a simple header-injection plugin:

Kong (Lua):

lua
local MyPlugin = {
  PRIORITY = 1000,
  VERSION = "1.0.0",
}

function MyPlugin:access(conf)
  kong.service.request.set_header(
    "X-Custom-Header",
    conf.header_value
  )
end

return MyPlugin

Zuplo (TypeScript):

TypeScripttypescript
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

export default async function (
  request: ZuploRequest,
  context: ZuploContext,
  options: { headerValue: string },
  policyName: string,
) {
  const newRequest = new ZuploRequest(request);
  newRequest.headers.set("X-Custom-Header", options.headerValue);
  return newRequest;
}

Key advantages of the TypeScript approach:

  • Full IDE support — Autocomplete, type checking, and inline documentation in VS Code or any TypeScript-capable editor.
  • npm ecosystem — Import any npm package for tasks like data validation, cryptography, or API calls.
  • Standard Web APIs — Zuplo uses standard Request, Response, and Headers objects. If you know the Fetch API, you know how to write Zuplo policies.
  • Easier testing — Unit test your policies like any TypeScript function.

Developer Portal Migration

Kong Developer Portal is a separate product that requires manual setup, documentation writing, and OpenAPI spec uploads. Teams using Kong’s Dev Portal must maintain it independently from their gateway configuration.

Zuplo’s developer portal is built into the platform and auto-generated from your OpenAPI spec. When you update your routes in routes.oas.json, the portal updates automatically. Features include:

  • Automatic API documentation — Generated directly from your OpenAPI specification.
  • API Explorer — Developers can test your API directly from the docs.
  • Self-service API key management — Consumers sign up, get keys, and manage them without your intervention.
  • Custom branding and pages — Add custom Markdown, MDX, or React pages to your portal.

There is no separate product to deploy, no documentation to manually sync, and no additional cost.

CI/CD and GitOps

Kong’s Workflow

With Kong, a typical CI/CD pipeline involves:

  1. Edit kong.yml declarative config or use the Admin API
  2. Run deck sync to push changes to the control plane
  3. Hope the control plane propagates to all data plane nodes
  4. Manage separate kong.yml files per environment
  5. Build custom GitHub Actions to coordinate deployments

Zuplo’s Workflow

Zuplo’s deployment model is Git-native:

  1. Your gateway configuration (routes.oas.json, policies.json, and custom TypeScript modules) lives in a GitHub repository
  2. Push to a branch, and Zuplo automatically creates a preview deployment
  3. Merge to main, and the production gateway updates across all 300+ edge locations
  4. Every deployment is immutable and versioned — rollback by reverting a commit
  5. Environment variables handle per-environment differences (staging vs. production)

There is no decK equivalent to install, no Admin API to manage, and no database state to keep in sync.

Migration Checklist and Timeline

A typical Kong-to-Zuplo migration follows three phases:

Phase 1: Setup and Configuration (Week 1)

  • Create a Zuplo account and project
  • Connect your GitHub repository
  • Export your Kong routes and services (deck dump)
  • Translate routes to routes.oas.json format
  • Configure authentication policies to match your Kong auth plugins
  • Set up rate limiting policies
  • Configure CORS policies
  • Add environment variables for backend URLs, secrets, and per-environment config

Phase 2: Custom Logic and Testing (Week 2)

  • Migrate custom Lua plugins to TypeScript policies
  • Set up request/response transformation policies
  • Configure the developer portal
  • Test all routes against your backend services
  • Validate authentication flows end-to-end
  • Run load tests to verify rate limiting behavior
  • Review logging and observability configuration

Phase 3: Cutover and Validation (Week 3)

  • Run Zuplo in parallel alongside Kong (both receiving traffic)
  • Compare response behavior between Kong and Zuplo
  • Gradually shift traffic from Kong to Zuplo using DNS
  • Monitor error rates, latency, and throughput
  • Complete DNS cutover to Zuplo
  • Decommission Kong infrastructure
  • Update developer portal URLs and API documentation

Rollback Strategy

Because Zuplo deployments are Git-based, rollback is straightforward:

  • Configuration rollback — Revert the Git commit and push. The previous gateway configuration deploys automatically.
  • DNS rollback — If you kept Kong running during the parallel phase, switch DNS back to Kong’s endpoints.

Frequently Asked Questions

Is Zuplo compatible with Kong plugins?

Zuplo uses a different extensibility model (TypeScript policies instead of Lua plugins), so Kong plugins do not run directly on Zuplo. However, most Kong plugin functionality has a built-in Zuplo equivalent or can be implemented as a short TypeScript policy. The plugin-to-policy mapping above covers the most common cases.

How long does a Kong migration take?

For most teams, a complete migration takes two to four weeks depending on the number of custom plugins and routes. Teams with straightforward configurations (standard auth, rate limiting, and proxying) can often complete the migration in under a week.

Do I need to change my backend services?

No. Zuplo proxies requests to your existing backends using the URL Rewrite handler. Your backend services do not need any changes — Zuplo forwards requests just like Kong does.

What about Kong’s database-backed consumers?

Zuplo provides a managed API key service with a REST API for consumer management. You can script the migration of consumers from Kong’s database to Zuplo’s service.

Can I run Zuplo alongside Kong during migration?

Yes. The recommended approach is to run both gateways in parallel during the cutover phase, using DNS or a load balancer to gradually shift traffic from Kong to Zuplo.

Next Steps

Ready to migrate? Sign up for a free Zuplo account and follow the Getting Started Guide to set up your first gateway in minutes.

For planning your migration: