Plugin ordering algorithms

Uses: Kong Gateway
Related Documentation
Minimum Version
Kong Gateway - 3.0

When a plugin must run before or after another plugin regardless of their priorities, use dynamic plugin ordering. By default, each plugin’s static priority decides the order that plugins run in. Adding an ordering rule to a plugin overrides that order so it runs before or after another plugin.

The plugin_ordering_algorithm setting in kong.conf tells Kong Gateway how to resolve the plugin ordering rules. Use this reference to help you predict the order and decide which algorithm to use.

Dynamic ordering only affects the access phase. All other phases (header_filter, body_filter, response, and log) always run in static priority order.

Algorithm comparison

The available algorithms are legacy and priority_preserving, with legacy as default.

legacy

priority_preserving v3.16+

How is the order determined? Places plugins from highest to lowest priority. Before it places a plugin, it places everything that plugin depends on, even if that chain sits low in the priority list. Places each configured plugin next to the plugin it references, then keeps the remaining plugins in priority order.
Should I use before or after? Both before and after create the same dependency. Writing the rule on either plugin gives the same order. priority_preserving moves a different plugin depending on which plugin carries the rule. A before B moves A, and B after A moves B.
Which plugins move? The plugin you configure moves, plus any plugin that sits between it and its dependencies in priority order. The plugin you configure moves. Unconfigured plugins keep their relative order.

Tip: Use priority_preserving if you want plugins without an ordering rule to keep their relative order.

Keep legacy if your existing configuration already depends on its order.

Upgrading Kong Gateway doesn’t change the algorithm, so your current access phase order stays the same until you migrate to priority_preserving.

Rule resolution example

Consider the following plugins, which have static priorities and one ordering rule:

Plugin

Priority

Ordering rule

Pre-Function 1000000 after: [opentelemetry]
Request Callout 812 None
OpenTelemetry 14 None

By priority alone, the order is Pre-Function, Request Callout, OpenTelemetry.

Under priority_preserving, Pre-Function has the highest priority but must wait for OpenTelemetry:

  1. Request Callout (812) and OpenTelemetry (14) are ready. Request Callout runs first.
  2. OpenTelemetry is the only plugin that’s ready, so it runs next.
  3. Pre-Function is now ready and runs last.

Under legacy, the walk reaches Pre-Function first and places its dependency, OpenTelemetry, before it. Request Callout is placed last.

The following table shows the result for each algorithm:

Algorithm

Order

legacy
  1. OpenTelemetry
  2. Pre-Function
  3. Request Callout
priority_preserving
  1. Request Callout
  2. OpenTelemetry
  3. Pre-Function

In both results, Pre-Function runs after OpenTelemetry. The difference is in the other plugins:

  • Under legacy, Request Callout moves from second to last, even though it has no rule.
  • Under priority_preserving, Request Callout only moves up one position to make room for Pre-Function.

Ordering behavior

The following sections describe how the algorithms handle specific rule configurations and request conditions.

Choosing between before and after

With legacy, A before: [B] and B after: [A] record the same dependency, so they always give the same order.

With priority_preserving, the plugin carrying the rule is the one that moves, so the same relationship can produce different orders depending on where you write it.

The following example uses four plugins, listed in priority order: Key Auth (1250), LDAP Auth (1200), Header Cert Auth (1009), and Response Transformer (800). Here’s how the order changes depending on the algorithm you use:

Configuration

priority_preserving order

legacy order

Response Transformer with before: [ldap-auth]
  1. Key Auth
  2. Response Transformer
  3. LDAP Auth
  4. Header Cert Auth
  1. Key Auth
  2. Response Transformer
  3. LDAP Auth
  4. Header Cert Auth
LDAP Auth with after: [response-transformer]
  1. Key Auth
  2. Header Cert Auth
  3. Response Transformer
  4. LDAP Auth
  1. Key Auth
  2. Response Transformer
  3. LDAP Auth
  4. Header Cert Auth

Unexpected placement when rules interact

When several rules interact, priority_preserving places each plugin next to its anchor without searching for the order that disturbs the fewest unconfigured plugins.

The following example uses Key Auth, LDAP Auth, Header Cert Auth, and Response Transformer, listed in priority order. If you set Header Cert Auth before Response Transformer and Response Transformer before Key Auth, the resulting order looks like this:

  1. Header Cert Auth
  2. Response Transformer
  3. Key Auth
  4. LDAP Auth

LDAP Auth has no rule but drops from second to last. The two rules only fix the relative order of Header Cert Auth, Response Transformer, and Key Auth, so LDAP Auth can run in any position and still satisfy them. For example, running LDAP Auth first is also valid. priority_preserving places each plugin next to its anchor, so it can move an unconfigured plugin further than necessary.

To keep a plugin in place, add a rule to that plugin. In this case, setting before: [header-cert-auth] on LDAP Auth makes LDAP Auth run before the other three plugins. In this case, LDAP Auth with before: [header-cert-auth] makes it run before the other three plugins.

Plugins with the same priority

When plugins share a priority, Kong Gateway orders them by plugin name in descending order. This applies to both algorithms and doesn’t depend on load order. A cloned plugin without a priority override inherits the priority of its source plugin. See cloned plugins for details.

Scoped plugins

Dynamic ordering runs for each request. A plugin scoped to a Route, Service, or Consumer only takes part in ordering for requests that match its scope. A scoped plugin that doesn’t match the request can still be the target of another plugin’s before or after rule. It doesn’t run, and its own ordering rules don’t apply. This means the order can differ between request paths.

Circular rules

If your rules contradict each other, for example Response Transformer with before: [key-auth] and Key Auth with before: [response-transformer], Kong Gateway reports a circular dependency error instead of picking an order.

With legacy, the message is:

There is a circular dependency in the graph. It is not possible to derive a topological sort.

With priority_preserving, the error message also lists the plugins that form the circular dependency.

Migrate from legacy to priority_preserving

The plugin_ordering_algorithm setting defaults to legacy, so upgrading Kong Gateway doesn’t change your current access phase order.

Migrating from legacy to priority_preserving takes the following steps:

  1. Set plugin_ordering_algorithm = priority_preserving in kong.conf, or set the KONG_PLUGIN_ORDERING_ALGORITHM environment variable, on every data plane.

    Use the same algorithm on every data plane. Data planes with different algorithms run the same configuration in a different order.

  2. Restart the data planes.
  3. Retest every Workspace that uses ordering. Its access phase order might change.

Note: plugin_ordering_algorithm is a node-level setting. It has no effect on Workspaces that don’t use ordering.

Limitations

The two algorithms have different behaviors, but dynamic plugin ordering also has limitations that apply no matter which algorithm you use, such as cascading deletes, performance, and validation. See Known limitations of dynamic plugin ordering before you use it in production.

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!