Skip to main content

Choosing an Apigee alternative: a policy-by-policy migration map for regulated teams

Planning an Apigee alternative? Map each Apigee policy, API product, and developer app to a self-hosted gateway that runs fully inside your regulated perimeter.

  • comparisons
  • migration
  • architecture
  • compliance
Zerq team

Most teams looking for an Apigee alternative this year did not plan to. They run Apigee Edge for Private Cloud in their own data center because their regulator, their security team, or their own outsourcing policy required it. The 4.53.00 release line reached end of life in April 2026, and Google's published release process now ties continued support to annual upgrades with a fixed support window per release. The strategic direction is clear from the product line: the future of Apigee is Apigee X, which runs in Google Cloud, or Apigee hybrid, which runs the runtime on your Kubernetes clusters but keeps the management plane in Google Cloud.

For a bank, a payer, or a government agency, neither option is a version upgrade. It is a change in where the control plane of your API perimeter lives. That turns a routine platform refresh into an outsourcing assessment, a data residency review, and a migration project, all at once. If you are going to rebuild every proxy bundle anyway, the reasonable question is what you should rebuild it on.

This post is the practical version of that question. It maps what an Apigee estate actually consists of (proxy bundles, policies, shared flows, API products, developer apps, analytics) to the equivalent constructs in a self-hosted gateway, and shows what the migration work looks like policy by policy. The short comparison lives at zerq.dev/compare/zerq-vs-apigee; this is the engineering version.

Why the Apigee migration paths do not fit regulated estates

Apigee is a capable platform, and for teams already committed to Google Cloud, Apigee X is a coherent destination. The friction for regulated teams is architectural, not functional.

Apigee hybrid is the option that looks closest to what Private Cloud customers have today, and it is where the mismatch shows most clearly. The runtime plane (message processors, the Cassandra datastore, the synchronizer) runs on your clusters. But the management plane, including the UI, the management API, and analytics processing, runs in Google Cloud. The runtime pulls configuration from Google and pushes analytics data back to it. That means the definition of every API you expose, the identity of every administrator, and the operational telemetry of your perimeter are processed outside your boundary. A fully air-gapped deployment is not something you configure; the design assumes connectivity to Google Cloud. For a defence ministry or a bank whose outsourcing register already lists too many critical third parties, that is the conversation that stops the project.

The second friction point is the policy model itself. An Apigee proxy is an XML bundle: a ProxyEndpoint, a TargetEndpoint, flows with conditions, and a chain of policies (VerifyAPIKey, SpikeArrest, Quota, AssignMessage, ServiceCallout, JavaScript, RaiseFault) attached to request and response steps. Shared flows and flow hooks layer on top. It works, but platform knowledge concentrates in the people who can read those bundles, and every migration path, including Google's own move from Edge to X, requires rebuilding them. Moving to Kong, AWS API Gateway, or Azure API Management would also mean rebuilding them, and most of those options either keep a vendor cloud in the management path or split gateway, portal, and analytics into separate products you then have to reconnect.

What an Apigee alternative actually has to replace

A workable Apigee alternative for a regulated team has to cover six things the estate depends on, without moving any of them outside the perimeter. Zerq's architecture is a single Go binary that serves gateway traffic, the management API, and the MCP endpoints, with a Next.js management UI and developer portal running alongside it. All configuration and all audit data live in your own MongoDB. There is no external control plane, nothing is sent to Zerq's systems during normal operation, and the same deployment runs fully offline.

The concept mapping looks like this:

Apigee constructZerq equivalentNotes
API proxy bundleProxy inside a collectionOne proxy per path and method, imported from OpenAPI
API productCollectionThe unit of access a client is granted
Developer app and API keyClient with one or more profilesProfile sets auth type, allowed methods, IP allowlist
VerifyAPIKeyProfile with token authChecked before any workflow runs
VerifyJWT / OAuthV2 (validate)Profile with jwt or oidc auth, or jwt_nodeValidates against your IdP or JWKS
SpikeArrest and QuotaPolicy attached to the clientrate_limit_* and quota_* fields
AssignMessage, ExtractVariablesset_node and expressions{{ $json['node_id'].field }}
ServiceCallouthttp_request_nodeWith timeout_ms and retry_config
JavaScript policycode_nodeJavaScript in config.code
XMLToJSON / JSONToXMLxml_nodeOptional SOAP body unwrapping
RaiseFaultresponse_nodeExplicit status, headers, and body
AnalyticsRequest logs and audit logsIn your MongoDB, not a vendor service

Two differences matter for planning. First, Zerq policies apply per client across all of that client's profiles, not per API product, so an Apigee setup with different quotas per product for the same app becomes separate clients or separate policies. Second, Zerq does not act as an OAuth authorization server the way Apigee's OAuthV2 GenerateAccessToken operation can. It validates tokens issued by your IdP, which is usually where regulated teams want token issuance to live anyway.

Access control: from developer apps to clients, profiles, and policies

The Apigee pattern of "app subscribes to product, key is checked, SpikeArrest and Quota run" collapses into gateway configuration rather than policy steps. Every request carries X-Client-ID and X-Profile-ID headers plus the credential the profile requires. The gateway checks, in order, that the client and profile are active, that the client is allowed the target collection, that authentication passes, that the method and source IP are allowed, and that the rate limit and quota are not exceeded. Only then does the request reach a proxy or workflow. The full model is in the security overview.

A policy that replaces a SpikeArrest plus monthly Quota pair looks like this, using the fields from the platform's policy model:

{
  "name": "Partner standard tier",
  "description": "Replaces SpikeArrest 600pm + Quota 1M/month from Apigee product 'accounts-standard'",
  "active": true,
  "rate_limit_interval": "1m",      // sliding window: 1m, 5m, or 1h
  "rate_limit_requests": 600,       // max requests per window, across all of the client's profiles
  "quota_interval": "30d",          // 1d, 7d, or 30d; 30d resets on the 1st of each month (UTC)
  "quota_requests": 1000000         // long-window cap; exceeding it returns 429 quota_exceeded
}

Clients over the limit receive 429 with rate_limit_exceeded or quota_exceeded, which is the behaviour most Apigee consumers already handle.

Proxy logic: from policy chains to workflows

Apigee proxies that only route and check keys need no workflow at all in Zerq; the proxy and the access profile cover them. The bundles that carry real logic map to the workflow builder, a visual pipeline of nodes attached to a proxy. Consider a common Apigee pattern: validate the request body with a JavaScript policy, forward to the accounts backend, call a customer-profile service with a ServiceCallout, merge the two with AssignMessage, and RaiseFault on errors. As a workflow:

{
  "nodes": [
    { "id": "http_trigger", "type": "http_trigger" },
    {
      "id": "check_body",
      "type": "validate_node",
      "config": {
        "schema": {
          "type": "object",
          "required": ["accountId"],
          "properties": { "accountId": { "type": "string" } }
        }
      },
      "inputs": { "value": "{{ $json['http_trigger'].request.body }}" }
    },
    { "id": "accounts", "type": "proxy_node" },
    {
      "id": "profile",
      "type": "http_request_node",
      "config": {
        "timeout_ms": 2000,
        "retry_config": { "max_attempts": 2, "backoff_ms": 250 },
        "credentials_id": "customer-profile-svc"
      },
      "inputs": {
        "url": "https://profile.internal/v1/customers/{{ $json['accounts'].response.body.customerId }}",
        "method": "GET"
      }
    },
    {
      "id": "shape",
      "type": "set_node",
      "config": {
        "assignments": {
          "account": "{{ $json['accounts'].response.body }}",
          "segment": "{{ $json['profile'].response.body.segment }}"
        }
      }
    },
    { "id": "ok", "type": "response_node", "config": { "status": 200 } },
    { "id": "bad_request", "type": "response_node", "config": { "status": 400, "body": { "error": "invalid_request" } } },
    { "id": "upstream_failed", "type": "response_node", "config": { "status": 502, "body": { "error": "upstream_unavailable" } } }
  ]
}

The validate_node branches on valid and invalid; the proxy_node and http_request_node branch on success and error. You wire those handles on the canvas rather than writing flow conditions in XML. The credentials_id points at a stored backend credential, so no secret lives in the workflow, and that credential can itself reference an environment variable injected from Vault instead of storing a value. Every save is versioned and audited, which replaces the revision history Apigee kept per bundle.

Analytics: from a vendor pipeline to your own MongoDB

In Apigee hybrid, analytics data leaves your clusters for Google Cloud processing. In Zerq, every gateway request writes a request log entry to your MongoDB. A migrated call looks like this:

{
  "method": "POST",
  "path": "/accounts/v1/lookup",
  "target_url": "https://core-accounts.internal/v1/lookup",
  "status": 200,
  "latency": 84,
  "client_ip": "10.40.2.17",
  "client_id": "66f1c2a9e4b0a1d2c3f40001",
  "profile_id": "66f1c2a9e4b0a1d2c3f40002",
  "collection": "Accounts",
  "request_id": "b7d3f0e2-5c1a-4e8b-9a77-2f6e1d0c4a13",
  "created_at": "2026-10-05T09:14:22Z"
}

client_id and profile_id replace Apigee's developer app dimension, collection replaces the API product, and request_id correlates the call with backend logs. Administrative changes go to a separate audit log with actor_id, actor_type, resource_type, action, ip_address, and the full request and response bodies of the change. A compliance officer with the dedicated Auditor role reads both without any permission to modify the platform, and the observability views filter by client, profile, path, status code, and time range.

Running the migration: a sequence that works

Teams that get through an Apigee migration without a freeze follow roughly the same order, one API product at a time:

  1. Export the OpenAPI 3.x specification for the API product. If you only have the proxy bundle, generate a spec from it or from the backend; Swagger 2.0 needs converting to 3.x first.
  2. In the Zerq management UI, open Collections, click Import from OpenAPI, upload the file, review the preview, and click Import. Zerq creates the collection from info.title, sets the target from servers[0].url, and creates one draft proxy per path and method.
  3. Correct the target endpoint and attach backend credentials, using environment-variable-backed values for anything that lived in an Apigee encrypted KVM.
  4. List the policies in the Apigee bundle. Delete the ones the gateway now handles (VerifyAPIKey, SpikeArrest, Quota, VerifyJWT), and rebuild the rest as workflow nodes on the proxies that need them.
  5. Create a policy per Apigee product tier, then a client per developer app, assign the collection and policy, and configure the profile auth type the partner already uses. Plan to issue new credentials to each partner rather than carrying Apigee consumer keys across.
  6. Enable Developer Portal access on the client and add the partner's authorized emails. They sign in with a magic link and see only their assigned collections.
  7. Publish the proxies, run both gateways in parallel, compare request logs against Apigee analytics for the same traffic, and shift traffic at your load balancer.

Once the core estate is moved, the AI question usually arrives. Agents connect through Gateway MCP with four tools, list_collections, list_endpoints, endpoint_details, and execute_endpoint, as a client with its own profile and policy. They see only the collections that client is assigned, and each execute_endpoint call writes the same request log as a partner integration. There is no second gateway to procure.

A checklist before you commit to X, hybrid, or something else

Put these questions to every destination, Apigee included:

  • If the vendor's cloud is unreachable for a week, can you still change configuration, onboard a partner, and read your own logs?
  • Where are API definitions, admin identities, and request analytics processed, and is that location already approved in your outsourcing register?
  • How many of your bundles are routing plus key checks, and how many contain JavaScript or Java callouts that someone must actually rebuild?
  • Can a platform engineer who did not write the bundle change a routing rule without learning a vendor-specific policy language?
  • Does analytics or advanced security cost extra per environment, or is it in the base license?
  • When AI agents need API access, do they go through the same credentials, limits, and audit trail as everything else?

What this looks like in practice

A regional bank runs Apigee Edge for Private Cloud with around sixty proxies: PSD2 interfaces for third-party providers, internal account and card APIs, and a handful of partner integrations. Most bundles are VerifyAPIKey or VerifyJWT, SpikeArrest, Quota, and a target. About a dozen carry JavaScript and ServiceCallout logic. The upgrade notice lands at the same time as the annual DORA register review, and the risk team will not approve a management plane in Google Cloud.

The platform team deploys Zerq on its existing Kubernetes platform against its own MongoDB and Keycloak. Routing-only proxies move first by OpenAPI import, with their Apigee product tiers recreated as policies. The TPP-facing PSD2 collections follow with mTLS profiles per provider. The dozen logic-heavy bundles become workflows; most turn out to be validation, one enrichment call, and response shaping, and only two need a code_node. Request logs are compared against Apigee analytics for two weeks before traffic is cut over. The outsourcing entry for the API management plane closes, and the auditors get a read-only audit role instead of exported reports.

What you end up with

An Apigee alternative for a regulated team is not a lift-and-shift of XML bundles; it is the same perimeter with the control plane moved back inside. Configuration, analytics, and audit data stay in your MongoDB instead of a vendor's management plane. Key checks, spike arrest, and quotas become gateway configuration instead of policy steps in every bundle. Policy chains become visual workflows that more of your team can read and change. Partners and AI agents share one access model, one portal, and one audit trail. And the license is a flat annual fee per environment, not a function of analytics add-ons and environment tiers.


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.