# Understanding the Easegress Pipeline Flow Mechanism and Jump Conditions

> Master Easegress pipeline flow and jump conditions. Learn how configurable filter chains and jumpIf fields redirect execution for efficient request processing.

- Repository: [MegaEase/easegress](https://github.com/megaease/easegress)
- Tags: deep-dive
- Published: 2026-03-07

---

**The Easegress pipeline flow mechanism processes requests through a configurable chain of filters where each node can define conditional jumps via the `jumpIf` field, redirecting execution to specific filter aliases or the built-in END filter based on filter return results.**

The Easegress API gateway from the `megaease/easegress` repository implements a flexible request processing architecture centered on **pipelines**—declarative chains of filters that execute conditionally. Understanding the Easegress pipeline flow mechanism and jump conditions is essential for building complex traffic management logic, as it allows developers to route requests dynamically based on filter outcomes rather than static sequences.

## Core Architecture of Easegress Pipelines

An Easegress pipeline consists of an ordered collection of **FlowNodes** defined in [`pkg/object/pipeline/pipeline.go`](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go). Each node represents a single processing step that can execute conditionally based on jump targets defined in the node's configuration.

### The FlowNode Structure

The fundamental building block is the **`FlowNode`** struct, which encapsulates filter metadata and jump conditions:

```go
type FlowNode struct {
    FilterName  string            `json:"filter" jsonschema:"required,format=urlname"`
    FilterAlias string            `json:"alias,omitempty"`
    Namespace   string            `json:"namespace,omitempty"`
    JumpIf      map[string]string `json:"jumpIf,omitempty"`
    filter      filters.Filter
}

```

*Source: [[`pkg/object/pipeline/pipeline.go`](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go)](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go#L80-L86)*

- **FilterName** identifies the filter implementation to invoke
- **FilterAlias** provides a short reference name used as jump targets
- **JumpIf** maps filter result strings to target aliases, enabling conditional flow control

### Pipeline Execution Flow

The **`Pipeline.Handle`** method serves as the entry point for request processing. It delegates to the private **`doHandle`** function, which implements the core execution algorithm:

```go
func (p *Pipeline) doHandle(ctx *context.Context, flow []FlowNode, stats []FilterStat) (string, []FilterStat, bool) {
    result, next, sawEnd := "", "", false

    for i := range flow {
        node := &flow[i]
        alias := node.filterAlias()

        // Skip nodes that are not the target of a previous JumpIf.
        if next != "" && next != alias {
            continue
        }

        // The built‑in END filter terminates the pipeline.
        if node.FilterName == BuiltInFilterEnd {
            sawEnd = true
            break
        }

        // Execute the filter.
        start := fasttime.Now()
        ctx.UseNamespace(node.Namespace)
        result = node.filter.Handle(ctx)
        stats = append(stats, FilterStat{
            Name:     alias,
            Kind:     node.filter.Kind().Name,
            Duration: fasttime.Since(start),
            Result:   result,
        })

        // Resolve jump target (if any) for the obtained result.
        var ok bool
        if next, ok = node.JumpIf[result]; result != "" && !ok {
            next = BuiltInFilterEnd
        }

        // END target forces termination.
        if next == BuiltInFilterEnd {
            sawEnd = true
            break
        }
    }
    return result, stats, sawEnd
}

```

*Source: [[`pkg/object/pipeline/pipeline.go`](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go)](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go#L71-L104)*

The algorithm processes nodes sequentially unless a **jump condition** redirects execution. When a filter returns a result, `doHandle` looks up the result in `node.JumpIf`. If found, execution continues at the matching alias; if not found, the pipeline jumps to `BuiltInFilterEnd` and terminates.

## How Jump Conditions Work in Easegress

Jump conditions transform linear pipelines into directed graphs, enabling conditional request processing paths based on authentication outcomes, rate limiting status, or business logic results.

### The JumpIf Mechanism

The **`JumpIf`** field is a `map[string]string` where:
- **Keys** represent filter result strings (e.g., `"Unauthorized"`, `"OverLimit"`)
- **Values** specify target filter aliases or the reserved `"END"` keyword

After executing a filter, the runtime evaluates the result against this map. If the result matches a key, the pipeline jumps to the corresponding target. This logic appears in lines 95-100 of the `doHandle` implementation:

```go
var ok bool
if next, ok = node.JumpIf[result]; result != "" && !ok {
    next = BuiltInFilterEnd
}

```

If a filter returns a non-empty result not present in `JumpIf`, the pipeline automatically terminates. This default behavior ensures that unexpected filter outcomes fail safely rather than continuing with potentially invalid request states.

### Built-in END Filter and Termination

The **`BuiltInFilterEnd`** constant represents a virtual filter that immediately terminates execution. Two conditions trigger termination:
1. Explicitly jumping to `"END"` via `jumpIf` configuration
2. Encountering a node with `FilterName == BuiltInFilterEnd` during iteration

When the algorithm detects either condition, it sets `sawEnd = true` and exits the processing loop, returning the final result to the caller.

## Validation and Safety Guarantees

Before a pipeline accepts traffic, the **`Spec.ValidateJumpIf`** method ensures all jump targets are resolvable and valid. This validation runs during configuration loading in [`pkg/object/pipeline/pipeline.go`](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go):

```go
func (s *Spec) ValidateJumpIf(specs map[string]filters.Spec) {
    validTargets := map[string]int{BuiltInFilterEnd: 1}
    for i := len(s.Flow) - 1; i >= 0; i-- {
        node := &s.Flow[i]
        if node.FilterName == BuiltInFilterEnd { continue }
        spec := specs[node.FilterName]
        results := filters.GetKind(spec.Kind()).Results
        for result, target := range node.JumpIf {
            if result != "" && !stringtool.StrInSlice(result, results) {
                panic(fmt.Errorf("filter %s: result %s is not in %v", node.FilterName, result, results))
            }
            if count := validTargets[target]; count == 0 {
                panic(fmt.Errorf("filter %s: target filter %s not found", node.FilterName, target))
            } else if count > 1 {
                panic(fmt.Errorf("duplicated filter name/alias: %s", target))
            }
        }
        validTargets[node.filterAlias()]++
    }
}

```

*Source: [[`pkg/object/pipeline/pipeline.go`](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go)](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go#L111-L138)*

The validator walks the flow **backwards** to build a set of valid jump targets, checking that:
- Each `JumpIf` result is a valid output of the filter's defined results
- Each target alias exists in the pipeline
- No duplicate aliases exist that could cause ambiguous jumps

## Configuring Pipeline Flows in YAML

Developers define the Easegress pipeline flow mechanism and jump conditions in YAML specifications. The `flow` array declares execution order and conditional branches:

```yaml
name: auth-pipeline
filters:
  - name: jwtAuth
    kind: JWTAuth
  - name: rateLimiter
    kind: RateLimiter
  - name: proxy
    kind: Proxy
flow:
  - filter: jwtAuth
    alias: auth
    jumpIf:
      Invalid: END
      Expired: rateLimiter
  - filter: rateLimiter
    alias: limiter
    jumpIf:
      OverLimit: END
  - filter: proxy
    alias: backend

```

In this configuration:
- **Valid JWTs** proceed directly to the proxy (no jump defined, continues to next node)
- **Expired tokens** jump to the rate limiter for additional validation
- **Invalid tokens** or **over-limit requests** terminate the pipeline immediately

The runtime translates these declarations into the `FlowNode` slice processed by `doHandle`. Each filter's return value determines the next hop in the execution graph.

## Summary

- **Easegress pipelines** use a linear `FlowNode` array processed by the `doHandle` method in [`pkg/object/pipeline/pipeline.go`](https://github.com/megaease/easegress/blob/main/pkg/object/pipeline/pipeline.go)
- **Jump conditions** are defined via the `jumpIf` map, which associates filter results with target filter aliases
- **Default termination** occurs when a filter returns a non-empty result not mapped in `jumpIf`, automatically routing to `BuiltInFilterEnd`
- **Validation** happens at startup through `ValidateJumpIf`, ensuring all jump targets exist and results are valid for their filter types
- **YAML configuration** combines filter definitions with a flow array that specifies execution order and conditional branching

## Frequently Asked Questions

### What happens if a filter returns a result not defined in jumpIf?

If a filter returns a non-empty result string that does not exist as a key in the node's `jumpIf` map, the pipeline automatically jumps to the built-in `END` filter and terminates execution. This safety mechanism prevents undefined behavior by ensuring only explicitly configured result codes allow continued processing.

### Can multiple filters share the same alias in a pipeline?

No. The `ValidateJumpIf` function explicitly checks for duplicate aliases during configuration validation. If two filters define the same alias, the validator panics with an error message indicating "duplicated filter name/alias", preventing ambiguous jump targets that could break the execution flow.

### How does the pipeline handle namespace isolation between filters?

Each `FlowNode` includes an optional `Namespace` field. Before executing a filter's `Handle` method, the runtime calls `ctx.UseNamespace(node.Namespace)` to switch the context to the appropriate namespace. This allows filters to maintain isolated state and configuration contexts while processing the same request through different pipeline stages.

### Is it possible to create loops or cycles using jumpIf conditions?

No, the current implementation does not prevent forward jumps only. While the validation walks backwards to confirm target existence, it does not enforce acyclic graphs. However, because jumps only skip forward to later nodes (or END), and the execution index always increments, infinite loops cannot occur within a single pipeline execution—the flow always progresses toward termination.