---
title: "Builder"
url: "/builder/"
kind: "page"
summary: "Compose an Arion configuration feature by feature and copy the YAML it produces."
---

> Arion site index: [/llms.txt](/llms.txt)

# Builder

Compose an Arion configuration feature by feature and copy the YAML it produces.

The Builder composes a configuration in the browser. `/builder/?recipe=<id>` opens it with a recipe loaded. The recipes below are what it offers; each lists the phrases the Builder reads, one feature per line, and the `arion.yaml` they compose.

## L7 load balancer (`l7-load-balancer`)

An HTTP listener in front of one cluster of three endpoints with least-request balancing, a health check, a circuit breaker, retries and a JSON access log.

Guide: [/guides/proxy/l7-load-balancer/index.md](/guides/proxy/l7-load-balancer/index.md)

````text
http listener on :8080
cluster web least_request 10.0.1.11:8080 10.0.1.12:8080 10.0.1.13:8080
health check /healthz every 5s
circuit breaker 1000 requests
retry 5xx,connect-failure 2 times
access log to stdout as json
````

````yaml
# arion.yaml, composed from 6 features.
logging:
  log_level: info
access_logging:
  blocking: false
envoy_bootstrap:
  static_resources:
    listeners:
      - name: http_8080
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: http_8080_chain
            filters:
              - name: http_gateway
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  access_log:
                    - name: envoy.access_loggers.stdout
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
                        log_format:
                          text_format: |
                            {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration_ms":"%DURATION%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_host":"%UPSTREAM_HOST%","authority":"%REQ(:AUTHORITY)%","user_agent":"%REQ(USER-AGENT)%","request_id":"%REQ(X-REQUEST-ID)%"}
                  http_filters:
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: http_8080_routes
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        retry_policy:
                          retry_on: 5xx,connect-failure
                          num_retries: 2
                        routes:
                          - match:
                              prefix: /
                            route:
                              cluster: web
    clusters:
      - name: web
        connect_timeout: 5s
        type: STATIC
        lb_policy: LEAST_REQUEST
        load_assignment:
          cluster_name: web
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.1.11, port_value: 8080 }
                - endpoint:
                    address:
                      socket_address: { address: 10.0.1.12, port_value: 8080 }
                - endpoint:
                    address:
                      socket_address: { address: 10.0.1.13, port_value: 8080 }
        health_checks:
          - timeout: 1s
            interval: 5s
            healthy_threshold: 3
            unhealthy_threshold: 2
            http_health_check:
              path: /healthz
        circuit_breakers:
          thresholds:
            - max_requests: 1000
````

## API gateway (`api-gateway`)

A rate limit, JWT authentication against your identity provider, a route to the API cluster with retries, and a health check.

Guide: [/guides/proxy/api-gateway/index.md](/guides/proxy/api-gateway/index.md)

````text
http listener on :8080
rate limit 100 per second
jwt issuer https://idp.example.com
route /api to cluster api
retry 5xx 2 times
cluster api least_request 10.0.0.12:8080
health check /healthz every 5s
````

````yaml
# arion.yaml, composed from 7 features.
logging:
  log_level: info
envoy_bootstrap:
  static_resources:
    listeners:
      - name: http_8080
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: http_8080_chain
            filters:
              - name: http_gateway
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  http_filters:
                    - name: envoy.filters.http.local_ratelimit
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
                        stat_prefix: http_local_rate_limiter
                        token_bucket:
                          max_tokens: 100
                          tokens_per_fill: 100
                          fill_interval: 1s
                    - name: envoy.filters.http.jwt_authn
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
                        providers:
                          idp:
                            issuer: https://idp.example.com
                            from_headers:
                              - name: Authorization
                                value_prefix: "Bearer "
                            payload_in_metadata: jwt_payload
                            remote_jwks:
                              http_uri:
                                uri: https://idp.example.com/.well-known/jwks.json
                                cluster: idp_jwks
                                timeout: 5s
                              cache_duration: 300s
                        rules:
                          - match:
                              prefix: /
                            requires:
                              provider_name: idp
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: http_8080_routes
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        retry_policy:
                          retry_on: 5xx
                          num_retries: 2
                        routes:
                          - match:
                              prefix: /api
                            route:
                              cluster: api
    clusters:
      - name: api
        connect_timeout: 5s
        type: STATIC
        lb_policy: LEAST_REQUEST
        load_assignment:
          cluster_name: api
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.0.12, port_value: 8080 }
        health_checks:
          - timeout: 1s
            interval: 5s
            healthy_threshold: 3
            unhealthy_threshold: 2
            http_health_check:
              path: /healthz
      - name: idp_jwks
        connect_timeout: 5s
        type: STRICT_DNS
        load_assignment:
          cluster_name: idp_jwks
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: idp.example.com, port_value: 443 }
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
            sni: idp.example.com
            common_tls_context:
              validation_context:
                trusted_ca:
                  filename: /etc/ssl/certs/ca-certificates.crt
````

## MCP gateway (`mcp-gateway`)

JWT authentication, and the MCP gateway exposing two REST endpoints as tools, one of them only to callers whose token carries role admin.

Guide: [/guides/mcp/mcp-gateway/index.md](/guides/mcp/mcp-gateway/index.md)

````text
http listener on :8080
jwt issuer https://idp.example.com audience mcp
mcp gateway
mcp tool api.get_status GET /v1/status on cluster tools_api listed
mcp tool api.delete_user DELETE /v1/users/{{id}} on cluster tools_api listed
tool api.delete_user requires claim role admin
cluster tools_api round_robin 10.0.4.11:8080
````

````yaml
# arion.yaml, composed from 7 features.
logging:
  log_level: info
envoy_bootstrap:
  static_resources:
    listeners:
      - name: http_8080
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: http_8080_chain
            filters:
              - name: http_gateway
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  http_filters:
                    - name: envoy.filters.http.jwt_authn
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
                        providers:
                          idp:
                            issuer: https://idp.example.com
                            audiences:
                              - mcp
                            from_headers:
                              - name: Authorization
                                value_prefix: "Bearer "
                            payload_in_metadata: jwt_payload
                            remote_jwks:
                              http_uri:
                                uri: https://idp.example.com/.well-known/jwks.json
                                cluster: idp_jwks
                                timeout: 5s
                              cache_duration: 300s
                        rules:
                          - match:
                              prefix: /
                            requires:
                              provider_name: idp
                    - name: arion.filters.http.mcp
                      typed_config:
                        "@type": type.googleapis.com/arion.extensions.filters.http.mcp.mcp_gateway.v3.McpGateway
                        server_info:
                          name: arion-mcp-gateway
                          version: 1.0.0
                        tools_mode: {}
                        tools:
                          - namespace: api
                            name: get_status
                            description: Calls GET /v1/status on cluster tools_api.
                            disclosure_mode: EAGER
                            input_schema:
                              inline_string: |
                                {"type": "object", "properties": {}}
                            rest_backend:
                              cluster: tools_api
                              method: GET
                              path: /v1/status
                          - namespace: api
                            name: delete_user
                            description: Calls DELETE /v1/users/{{id}} on cluster tools_api.
                            disclosure_mode: EAGER
                            input_schema:
                              inline_string: |
                                {"type": "object", "properties": {"id": {"type": "string"}}, "required": ["id"]}
                            rbac:
                              action: ALLOW
                              permissions:
                                - jwt_claim:
                                    field: role
                                    value: admin
                            rest_backend:
                              cluster: tools_api
                              method: DELETE
                              path: /v1/users/{{id}}
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: http_8080_routes
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        routes:
                          - match:
                              prefix: /
                            route:
                              cluster: tools_api
    clusters:
      - name: tools_api
        connect_timeout: 5s
        type: STATIC
        load_assignment:
          cluster_name: tools_api
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.4.11, port_value: 8080 }
      - name: idp_jwks
        connect_timeout: 5s
        type: STRICT_DNS
        load_assignment:
          cluster_name: idp_jwks
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: idp.example.com, port_value: 443 }
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
            sni: idp.example.com
            common_tls_context:
              validation_context:
                trusted_ca:
                  filename: /etc/ssl/certs/ca-certificates.crt
````

## MCP code mode (`mcp-code-mode`)

JWT authentication, and the MCP gateway in code mode: agents get one execute tool and send TypeScript that composes two REST tools in a sandbox.

Guide: [/guides/mcp/code-mode-for-agents/index.md](/guides/mcp/code-mode-for-agents/index.md)

````text
http listener on :8080
jwt issuer https://idp.example.com audience mcp
mcp gateway named support-tools
mcp tool support.recent_tickets GET /v1/tickets on cluster support_api
mcp tool support.create_ticket POST /v1/tickets on cluster support_api
code mode timeout 20s calls 50
cluster support_api round_robin 10.0.4.11:8080
````

````yaml
# arion.yaml, composed from 7 features.
logging:
  log_level: info
envoy_bootstrap:
  static_resources:
    listeners:
      - name: http_8080
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: http_8080_chain
            filters:
              - name: http_gateway
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  http_filters:
                    - name: envoy.filters.http.jwt_authn
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
                        providers:
                          idp:
                            issuer: https://idp.example.com
                            audiences:
                              - mcp
                            from_headers:
                              - name: Authorization
                                value_prefix: "Bearer "
                            payload_in_metadata: jwt_payload
                            remote_jwks:
                              http_uri:
                                uri: https://idp.example.com/.well-known/jwks.json
                                cluster: idp_jwks
                                timeout: 5s
                              cache_duration: 300s
                        rules:
                          - match:
                              prefix: /
                            requires:
                              provider_name: idp
                    - name: arion.filters.http.mcp
                      typed_config:
                        "@type": type.googleapis.com/arion.extensions.filters.http.mcp.mcp_gateway.v3.McpGateway
                        server_info:
                          name: support-tools
                          version: 1.0.0
                        code_mode:
                          execution_timeout: 20s
                          max_host_calls: 50
                        tools:
                          - namespace: support
                            name: recent_tickets
                            description: Calls GET /v1/tickets on cluster support_api.
                            input_schema:
                              inline_string: |
                                {"type": "object", "properties": {}}
                            rest_backend:
                              cluster: support_api
                              method: GET
                              path: /v1/tickets
                          - namespace: support
                            name: create_ticket
                            description: Calls POST /v1/tickets on cluster support_api.
                            input_schema:
                              inline_string: |
                                {"type": "object", "properties": {}}
                            rest_backend:
                              cluster: support_api
                              method: POST
                              path: /v1/tickets
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: http_8080_routes
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        routes:
                          - match:
                              prefix: /
                            route:
                              cluster: support_api
    clusters:
      - name: support_api
        connect_timeout: 5s
        type: STATIC
        load_assignment:
          cluster_name: support_api
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.4.11, port_value: 8080 }
      - name: idp_jwks
        connect_timeout: 5s
        type: STRICT_DNS
        load_assignment:
          cluster_name: idp_jwks
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: idp.example.com, port_value: 443 }
        transport_socket:
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
            sni: idp.example.com
            common_tls_context:
              validation_context:
                trusted_ca:
                  filename: /etc/ssl/certs/ca-certificates.crt
````

## Canary release (`canary-release`)

An HTTP listener that sends 10% of the traffic to a canary cluster and the rest to the stable one, a health check on each cluster, and retries.

Guide: [/guides/proxy/canary-with-weighted-clusters/index.md](/guides/proxy/canary-with-weighted-clusters/index.md)

````text
http listener on :8080
route / to cluster stable
send 10% of / to cluster canary
cluster stable least_request 10.0.2.11:8080 10.0.2.12:8080
health check /healthz every 5s
cluster canary round_robin 10.0.2.21:8080
health check /healthz every 5s
retry 5xx 2 times
````

````yaml
# arion.yaml, composed from 8 features.
logging:
  log_level: info
envoy_bootstrap:
  static_resources:
    listeners:
      - name: http_8080
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: http_8080_chain
            filters:
              - name: http_gateway
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  http_filters:
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: http_8080_routes
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        retry_policy:
                          retry_on: 5xx
                          num_retries: 2
                        routes:
                          - match:
                              prefix: /
                            route:
                              weighted_clusters:
                                clusters:
                                  - name: stable
                                    weight: 90
                                  - name: canary
                                    weight: 10
    clusters:
      - name: stable
        connect_timeout: 5s
        type: STATIC
        lb_policy: LEAST_REQUEST
        load_assignment:
          cluster_name: stable
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.2.11, port_value: 8080 }
                - endpoint:
                    address:
                      socket_address: { address: 10.0.2.12, port_value: 8080 }
        health_checks:
          - timeout: 1s
            interval: 5s
            healthy_threshold: 3
            unhealthy_threshold: 2
            http_health_check:
              path: /healthz
      - name: canary
        connect_timeout: 5s
        type: STATIC
        load_assignment:
          cluster_name: canary
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.2.21, port_value: 8080 }
        health_checks:
          - timeout: 1s
            interval: 5s
            healthy_threshold: 3
            unhealthy_threshold: 2
            http_health_check:
              path: /healthz
````

## TCP proxy (`tcp-proxy`)

A TCP listener in front of two Postgres servers, with PROXY protocol, a connection limit, an IP allow list and a TCP health check.

Guide: [/guides/proxy/route-tcp-at-l4/index.md](/guides/proxy/route-tcp-at-l4/index.md)

````text
tcp proxy on :5432 to cluster postgres
proxy protocol
connection limit 1000
allow ip 10.0.0.0/8
cluster postgres round_robin 10.0.3.11:5432 10.0.3.12:5432
tcp health check every 5s
````

````yaml
# arion.yaml, composed from 6 features.
logging:
  log_level: info
envoy_bootstrap:
  static_resources:
    listeners:
      - name: tcp_5432
        address:
          socket_address: { address: 0.0.0.0, port_value: 5432 }
        listener_filters:
          - name: envoy.filters.listener.proxy_protocol
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol
        filter_chains:
          - name: tcp_5432_chain
            filters:
              - name: envoy.filters.network.connection_limit
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.connection_limit.v3.ConnectionLimit
                  stat_prefix: cx_limit_tcp_5432
                  max_connections: 1000
              - name: envoy.filters.network.rbac
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC
                  rules:
                    action: ALLOW
                    policies:
                      allowed-clients:
                        permissions:
                          - any: true
                        principals:
                          - direct_remote_ip: { address_prefix: 10.0.0.0, prefix_len: 8 }
              - name: envoy.filters.network.tcp_proxy
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
                  cluster: postgres
    clusters:
      - name: postgres
        connect_timeout: 5s
        type: STATIC
        load_assignment:
          cluster_name: postgres
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.3.11, port_value: 5432 }
                - endpoint:
                    address:
                      socket_address: { address: 10.0.3.12, port_value: 5432 }
        health_checks:
          - timeout: 1s
            interval: 5s
            healthy_threshold: 3
            unhealthy_threshold: 2
            tcp_health_check: {}
````

## Wasm filter (`wasm-filter`)

An HTTP listener that runs your own Wasm filter, built with the Arion Wasm SDK, ahead of the router.

Guide: [/guides/extend/first-wasm-filter/index.md](/guides/extend/first-wasm-filter/index.md)

````text
http listener on :8080
wasm filter my_filter from /etc/arion/wasm/my_filter.wasm
route / to cluster app
cluster app round_robin 10.0.5.11:8080
````

````yaml
# arion.yaml, composed from 4 features.
logging:
  log_level: info
envoy_bootstrap:
  static_resources:
    listeners:
      - name: http_8080
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: http_8080_chain
            filters:
              - name: http_gateway
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  http_filters:
                    - name: arion.filters.http.wasm.my_filter
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
                        config:
                          name: my_filter
                          vm_config:
                            code:
                              local:
                                filename: /etc/arion/wasm/my_filter.wasm
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: http_8080_routes
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        routes:
                          - match:
                              prefix: /
                            route:
                              cluster: app
    clusters:
      - name: app
        connect_timeout: 5s
        type: STATIC
        load_assignment:
          cluster_name: app
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 10.0.5.11, port_value: 8080 }
````
