---
title: "Migrating from Kong to Zuplo: Plugin Mapping, Architecture Translation, and Step-by-Step Guide"
description: "A practical guide for teams migrating from Kong Gateway to Zuplo, covering plugin-to-policy mapping, config translation, and a phased migration plan."
canonicalUrl: "https://zuplo.com/learning-center/migrate-from-kong-to-zuplo"
pageType: "learning-center"
authors: "nate"
tags: "API Gateway, Tutorial"
image: "https://zuplo.com/og?text=Migrating%20from%20Kong%20to%20Zuplo"
---
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](#why-teams-migrate-from-kong)
2. [Architecture Comparison](#architecture-comparison)
3. [Plugin-to-Policy Mapping](#plugin-to-policy-mapping)
4. [Translating Kong Configuration to Zuplo](#translating-kong-configuration-to-zuplo)
5. [Authentication Migration](#authentication-migration)
6. [Rate Limiting Migration](#rate-limiting-migration)
7. [Custom Plugin Migration](#custom-plugin-migration)
8. [Developer Portal Migration](#developer-portal-migration)
9. [CI/CD and GitOps](#cicd-and-gitops)
10. [Migration Checklist and Timeline](#migration-checklist-and-timeline)
11. [Frequently Asked Questions](#frequently-asked-questions)
12. [Next Steps](#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-auth** →
  [API Key Authentication](https://zuplo.com/docs/policies/api-key-inbound) —
  Zuplo's built-in API key policy includes a managed key service with
  self-service key management through the developer portal.
- **jwt** →
  [JWT Auth Policy (OpenID)](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
  — Validates JWT tokens from any OpenID-compliant provider. Works with Auth0,
  Okta, Azure AD, and others out of the box.
- **basic-auth** →
  [Basic Auth Policy](https://zuplo.com/docs/policies/basic-auth-inbound) —
  Built-in support for HTTP Basic authentication.
- **oauth2** →
  [JWT Auth Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound) —
  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-auth** →
  [LDAP Auth Policy](https://zuplo.com/docs/policies/ldap-auth-inbound) — Direct
  LDAP authentication support.
- **mtls-auth** →
  [mTLS Auth Policy](https://zuplo.com/docs/policies/mtls-auth-inbound) — Mutual
  TLS authentication for service-to-service communication.

### Traffic Control

- **rate-limiting** →
  [Rate Limiting Policy](https://zuplo.com/docs/policies/rate-limit-inbound) —
  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-limiting** →
  [Request Size Limit Policy](https://zuplo.com/docs/policies/request-size-limit-inbound)
  — Built-in policy to enforce a maximum request body size in bytes.
- **ip-restriction** →
  [IP Restriction Policy](https://zuplo.com/docs/policies/ip-restriction-inbound)
  — 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](https://zuplo.com/docs/policies/custom-code-inbound).
- **cors** →
  [Custom CORS Policy](https://zuplo.com/docs/programmable-api/custom-cors-policy)
  — Configure allowed origins, methods, and headers per route. Supports wildcard
  subdomains and environment variables.

### Request/Response Transformation

- **request-transformer** →
  [Add or Set Request Headers](https://zuplo.com/docs/policies/set-headers-inbound)
  - [Transform Request Body](https://zuplo.com/docs/policies/transform-body-inbound)
    — Combine built-in header policies with custom TypeScript body
    transformation.
- **response-transformer** →
  [Set Response Headers](https://zuplo.com/docs/policies/set-headers-outbound)
  - [Transform Response Body](https://zuplo.com/docs/policies/transform-body-outbound)
    — Modify outgoing responses with built-in or custom policies.

### Security

- **acl** →
  [RBAC Authorization Policy](https://zuplo.com/docs/policies/rbac-policy-inbound)
  — 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-detection** →
  [Bot Detection Policy](https://zuplo.com/docs/policies/bot-detection-inbound)
  (enterprise) — Bot scoring and detection for identifying automated traffic.
  For cryptographic bot identity verification (such as verifying Googlebot), see
  the
  [Web Bot Auth Policy](https://zuplo.com/docs/policies/web-bot-auth-inbound).

### 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](https://zuplo.com/docs)
  for details on logging integrations.

### Validation

- **request-validator** →
  [Request Validation Policy](https://zuplo.com/docs/policies/request-validation-inbound)
  — 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):

```yaml
# 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:

```json
{
  "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`:

```json
{
  "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](https://zuplo.com/docs/policies/api-key-inbound)
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](https://zuplo.com/docs/articles/api-key-api).

### JWT Authentication

Kong's `jwt` plugin validates JWT tokens against stored consumer credentials.
Zuplo's
[JWT Auth Policy](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
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:

```json
{
  "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](https://zuplo.com/docs/policies/rate-limit-inbound)
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:

```json
{
  "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](https://zuplo.com/docs/policies/custom-code-inbound)
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):**

```typescript
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](https://zuplo.com/docs/dev-portal/introduction).
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](https://zuplo.com/docs/articles/api-key-api).
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](https://portal.zuplo.com) and follow the
[Getting Started Guide](https://zuplo.com/docs/articles/step-1-setup-basic-gateway)
to set up your first gateway in minutes.

For planning your migration:

- [Kong vs Zuplo: API Gateway Comparison](/learning-center/kong-vs-zuplo) — A
  detailed comparison of architecture, developer experience, pricing, and when
  to choose each platform.
- [Compare Zuplo and Kong](/api-gateways/kong-alternative-zuplo) — See a
  detailed feature-by-feature comparison.
- [Best API Management Platforms (2026)](/learning-center/best-api-management-platforms-2026)
  — Compare Zuplo, Kong, and five other platforms across developer experience,
  performance, and AI capabilities.
- [Policy Catalog](https://zuplo.com/docs/policies/overview) — Browse all
  available built-in policies.
- [Custom Policies Documentation](https://zuplo.com/docs/policies/custom-code-inbound)
  — Learn how to write your own TypeScript policies.