Octopus
1.x
Docs/Octopus/Routing
Open

Reading10 min
Updated31 Jul 2026
Sourcev1/concepts/routing.mdx

Routing

Learn how Octopus routes incoming requests to upstream services.

Overview01

Octopus uses a trie-based router for efficient path matching. Routes are defined in configuration and can be dynamically updated through FARP, the Kubernetes operator, or the admin API.

Warning

This page explains routing ideas (path matching, parameters, priority, prefix rewriting). Some examples below show fields and routing modes that are not part of the current configuration schema (for example match_type, conditions, route_groups, route-level retries, and rate_limit.requests_per_second). For the source-verified routes[] schema — path, methods, upstream, priority, strip_prefix, add_prefix, auth_provider/skip_auth/require_roles/require_scopes/authz_rule, timeout, rate_limit (requests_per_window + window_size), and cors — always defer to Routes. Note rate_limit and cors are stored but not enforced in the live chain today (see Middleware).

Basic Routing02

Simple Path Match

routes:
  - path: /api/users
    upstream: user-service
    methods: [GET, POST]

Matches:

  • GET /api/users

  • POST /api/users

  • PUT /api/users ❌ (method not allowed)

  • GET /api/users/123 ❌ (path doesn't match)

Wildcard Matching

routes:
  - path: /api/users/*
    upstream: user-service
    methods: [GET, POST, PUT, DELETE]

Matches:

  • /api/users/123

  • /api/users/123/posts

  • /api/users/123/posts/456

  • /api/users ❌ (no wildcard match)

Path Parameters

routes:
  - path: /api/users/:id
    upstream: user-service
    methods: [GET, PUT, DELETE]
  
  - path: /api/users/:id/posts/:post_id
    upstream: user-service
    methods: [GET]

Matches:

  • /api/users/123id=123

  • /api/users/456/posts/789id=456, post_id=789

Note

Path parameters are available in middleware and can be forwarded to upstreams.

Routing Strategies03

Exact Match

routes:
  - path: /health
    upstream: health-service
    match_type: exact

Only matches /health exactly.

Prefix Match

routes:
  - path: /api/
    upstream: api-service
    match_type: prefix

Matches any path starting with /api/.

Regex Match

routes:
  - path: /api/v[0-9]+/users
    upstream: user-service
    match_type: regex

Matches /api/v1/users, /api/v2/users, etc.

Warning

Regex routing is slower than trie-based matching. Use sparingly.

Route Priority04

When multiple routes match, priority determines which one is used:

routes:
  # Highest priority (exact match)
  - path: /api/users/me
    upstream: auth-service
    priority: 100
  
  # Medium priority (path parameter)
  - path: /api/users/:id
    upstream: user-service
    priority: 50
  
  # Lowest priority (wildcard)
  - path: /api/*
    upstream: default-service
    priority: 10

Request to /api/users/me:

  1. Matches all three routes

  2. Routes to auth-service (highest priority)

Default Priority

  • Exact matches: 100

  • Path parameters: 50

  • Wildcards: 10

  • Custom: Any value you specify

Method Routing05

Specific Methods

routes:
  - path: /api/users
    upstream: user-service
    methods: [GET, POST]

Method-Specific Configuration

routes:
  - path: /api/users
    upstream: user-service
    methods:
      - method: GET
        timeout: 10s
      - method: POST
        timeout: 30s
        rate_limit:
          requests_per_second: 10

HEAD and OPTIONS

routes:
  - path: /api/users
    upstream: user-service
    methods: [GET, POST, PUT, DELETE]
    auto_head: true      # Auto-handle HEAD requests
    auto_options: true   # Auto-handle OPTIONS (CORS)

Host-Based Routing06

Route based on the Host header:

routes:
  - host: api.example.com
    path: /*
    upstream: api-v1
  
  - host: api-v2.example.com
    path: /*
    upstream: api-v2
  
  - host: "*.staging.example.com"
    path: /*
    upstream: staging-api

Header-Based Routing07

Route based on request headers:

routes:
  - path: /api/*
    upstream: api-v2
    conditions:
      - header: X-API-Version
        value: v2
  
  - path: /api/*
    upstream: api-v1  # Default

Multiple Conditions

routes:
  - path: /api/*
    upstream: beta-api
    conditions:
      - header: X-Beta-User
        value: "true"
      - header: X-API-Key
        exists: true

All conditions must match.

Query Parameter Routing08

routes:
  - path: /api/search
    upstream: search-v2
    conditions:
      - query: version
        value: v2
  
  - path: /api/search
    upstream: search-v1

Path Manipulation09

Octopus rewrites the path before proxying using two fields: strip_prefix (removed from the front of the path) and add_prefix (prepended). When both are set, the prefix is stripped first and then the new prefix is added. This is the prefix rewriting applied in handler.rs for HTTP, WebSocket, SSE, and gRPC.

Strip Prefix

routes:
  - path: /api/v1/*
    upstream: user-service
    strip_prefix: /api/v1   # Forward without the prefix

Request: /api/v1/users/123 Forwarded: /users/123

Add Prefix

routes:
  - path: /*
    upstream: service
    add_prefix: /v2

Request: /users/123 Forwarded: /v2/users/123

Note

There is no regex-capture rewrite field. Path rewriting is limited to strip_prefix and add_prefix. See Routes.

Timeout Configuration10

routes:
  - path: /api/users
    upstream: user-service
    timeout: 30s          # Total request timeout
    connect_timeout: 5s   # Connection timeout
    read_timeout: 20s     # Read timeout

Retries11

Note

Routes have no retries/retry_on fields. Retry behavior lives in the proxy layer (proxy.proxy_with_retry), and load balancing, health checks, and circuit breaking are configured per upstream, not per route. See Upstreams.

Load Balancing12

Load-balancing policy is set on the upstream via lb_policy, not on the route:

upstreams:
  - name: api-service
    lb_policy: least_connections
    instances:
      - id: api-1
        host: 10.0.0.11
        port: 8080

See Load Balancing and Upstreams for details.

Circuit Breaker13

Circuit breakers are configured per upstream, not per route:

upstreams:
  - name: order-service
    circuit_breaker:
      error_threshold: 50.0
      min_requests: 20
      timeout: 30s
    instances:
      - id: order-1
        host: 10.0.0.21
        port: 8080

See Circuit Breaker for details.

WebSocket Routing14

routes:
  - path: /ws
    upstream: websocket-service
    protocol: websocket
    timeout: 3600s  # Long timeout for WS connections

gRPC Routing15

routes:
  - path: /grpc.*
    upstream: grpc-service
    protocol: grpc
    grpc:
      transcoding: true  # Enable HTTP→gRPC transcoding

Route Metadata16

Attach metadata to routes for logging/metrics:

routes:
  - path: /api/users
    upstream: user-service
    metadata:
      team: identity
      version: v2
      cost_center: eng-001

Dynamic Routes17

Routes can be added/removed dynamically:

Via Admin API

# Add route
curl -X POST http://localhost:9090/_/routes \
  -H "Content-Type: application/json" \
  -d '{
    "path": "/api/new",
    "upstream": "new-service",
    "methods": ["GET"]
  }'

# Remove route
curl -X DELETE http://localhost:9090/_/routes/api-new

Via FARP

FARP automatically creates routes from service manifests:

{
  "service_name": "user-service",
  "schemas": [{
    "type": "openapi",
    "location": { "url": "http://user-service/openapi.json" }
  }]
}

See FARP Protocol for details.

Route Groups18

Organize routes with common configuration:

route_groups:
  - name: api-v1
    prefix: /api/v1
    middleware: [auth, rate_limit]
    timeout: 30s
    routes:
      - path: /users
        upstream: user-service
      - path: /orders
        upstream: order-service
  
  - name: api-v2
    prefix: /api/v2
    middleware: [auth, rate_limit, compression]
    timeout: 60s
    routes:
      - path: /users
        upstream: user-service-v2
      - path: /orders
        upstream: order-service-v2

Internal Routes19

Routes handled by the gateway itself:

routes:
  - path: /_/health
    internal: true
    handler: health_check
  
  - path: /_/metrics
    internal: true
    handler: metrics
  
  - path: /_/config
    internal: true
    handler: config
    auth_required: true

Route Validation20

Validate routes on startup:

octopus validate --config config.yaml

Checks:

  • No duplicate paths with same priority

  • All upstreams exist

  • Valid path patterns

  • Valid method names

  • Valid condition syntax

Performance21

Lookup Time

  • Exact match: O(k) where k is path length

  • Path parameters: O(k * p) where p is number of parameters

  • Wildcard: O(k * n) where n is number of wildcards

  • Regex: O(n) where n is number of regex routes

Memory Usage

  • Per route: ~128 bytes

  • Trie node: ~64 bytes

  • Path parameter: ~32 bytes

Optimization Tips

  1. Use exact matches when possible

  2. Limit regex routing

  3. Order routes by frequency (most common first)

  4. Use route groups for common configuration

  5. Avoid deep path nesting

Examples22

RESTful API

routes:
  # List users
  - path: /api/users
    upstream: user-service
    methods: [GET]
  
  # Create user
  - path: /api/users
    upstream: user-service
    methods: [POST]
    rate_limit:
      requests_per_second: 10
  
  # Get/update/delete user
  - path: /api/users/:id
    upstream: user-service
    methods: [GET, PUT, DELETE]

Microservices

routes:
  # User service
  - path: /users/*
    upstream: user-service
  
  # Order service
  - path: /orders/*
    upstream: order-service
  
  # Product service
  - path: /products/*
    upstream: product-service
  
  # Payment service (with circuit breaker)
  - path: /payments/*
    upstream: payment-service
    circuit_breaker:
      enabled: true
      failure_threshold: 3

API Versioning

routes:
  # v1 API
  - path: /api/v1/*
    upstream: api-v1
    timeout: 30s
  
  # v2 API
  - path: /api/v2/*
    upstream: api-v2
    timeout: 60s
    middleware: [auth, rate_limit, compression]
  
  # Default to latest
  - path: /api/*
    upstream: api-v2

Next Steps23