---
title: "File format"
url: "/reference/configuration/file-format/"
kind: "reference"
summary: "Every top-level key of the Arion configuration file: runtime, logging, access_logging, metrics, timezone and the bootstrap forms."
---

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

# File format

Every top-level key of the Arion configuration file: runtime, logging, access_logging, metrics, timezone and the bootstrap forms.

The Arion configuration file is a single YAML document, passed with `--config`, whose top-level keys tune the process and carry the proxy resources inside `envoy_bootstrap`.

## Top-level keys

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `runtime` | object | no | see below | Worker cores, Tokio runtimes and scheduler tuning. |
| `logging` | object | no | stdout, `error` | Process log level and destination. |
| `access_logging` | object | no | unset | Access-log pipeline tuning, rotation and custom operators. |
| `metrics` | object | no | unset | Metric partition keys, renames and custom metrics. |
| `timezone` | object | no | UTC | Local timezone for log timestamps. |
| `envoy_bootstrap` | object | no | unset | Proxy resources in Envoy Bootstrap form. The canonical dialect. |
| `bootstrap` | object | no | empty | Proxy resources in Arion's native form. Mutually exclusive with `envoy_bootstrap`. |

Setting both `bootstrap` and `envoy_bootstrap` fails with `only one of 'bootstrap' and 'envoy_bootstrap' may be set`. If neither is present, the file contributes no proxy resources; a bootstrap must then come from the `--with-envoy-bootstrap` flag (see [Command line](@/reference/configuration/cli.md)), which also replaces either key when both a file and the flag are given.

## runtime

Values here are overridden by [environment variables](@/reference/configuration/environment-variables.md), then by [command-line flags](@/reference/configuration/cli.md), in that order of precedence (environment wins).

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `num_cpus` | integer ≥ 1 | no | detected CPUs | Cores to use. Detection honours container cgroup CPU limits (v1 and v2, quota rounded up). |
| `num_runtimes` | integer ≥ 1 | no | `1` | Number of Tokio worker runtimes the cores are split across. |
| `num_service_threads` | integer ≥ 1 | no | `1` | Threads for background service tasks. |
| `global_queue_interval` | integer ≥ 1 | no | Tokio default | Scheduler ticks between global queue polls. |
| `event_interval` | integer | no | Tokio default | Scheduler ticks between I/O event polls. |
| `max_io_events_per_tick` | integer ≥ 1 | no | Tokio default | Maximum I/O events processed per tick. |
| `affinity_strategy` | object | no | unset | Pin worker threads to cores: `type: auto`, or `type: nodes` / `type: runtimes` with `map`, a list of core-id lists. |
| `codemode.pool_capacity` | integer ≥ 1 | no | `128` | Sandboxes the whole process can run at once for MCP [code mode](@/docs/mcp-gateway/code-mode.md). A listener's `max_concurrent_executions` cannot exceed it. Needs the `codemode` build feature. |
| `codemode.max_memory_bytes` | integer ≥ 1 | no | `67108864` (64 MiB) | Largest memory any one code-mode sandbox may use. A listener's `memory_limit_bytes` cannot exceed it. |

```yaml,name=arion.yaml,arion=fragment
runtime:
  num_cpus: 2
  num_runtimes: 2
  event_interval: 31
  affinity_strategy:
    type: auto
  codemode:
    pool_capacity: 64
    max_memory_bytes: 33554432
```

The `codemode` values size one sandbox pool shared by every code-mode listener in the process. It is created when the first code-mode listener loads.

## logging

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `log_level` | string | no | `error` | A `tracing` filter directive, e.g. `info` or `arion_lib=debug,info`. The `RUST_LOG` environment variable overrides it. |
| `log_directory` | string | no | `.` | Directory for the log file when `log_file` is set. |
| `log_file` | string | no | unset | File name for process logs. When set, logs move from stdout to an hourly-rotated file. |

```yaml,name=arion.yaml,arion=fragment
logging:
  log_level: "info"
  log_directory: /var/log/arion
  log_file: arion.log
```

## access_logging

Tunes the shared access-log pipeline. The log destinations and formats themselves are configured per listener and per HTTP connection manager inside `envoy_bootstrap` — see [access logs](@/docs/observe/access-logs.md).

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `num_instances` | integer ≥ 1 | no | `1` | Number of access-log writer instances. |
| `queue_length` | integer ≥ 1 | no | `1024` | Queue length per writer between workers and the log writer. |
| `log_rotation` | string | no | unset | Rotation frequency for file sinks: `minutely`, `hourly` or `daily`. |
| `log_max_size` | integer | no | unset | Maximum size in bytes before a file rotates. |
| `max_log_files` | integer ≥ 1 | no | `10` | Rotated files kept before the oldest is deleted. |
| `blocking` | bool | yes | — | When `true`, workers block if the queue is full instead of dropping entries. |
| `incoming_request_header` | string | no | unset | Header holding a base64-encoded JSON object, read when the request arrives; its keys feed `custom_operators`. |
| `ext_proc_request_header` | string | no | unset | Same, read from the ext_proc request exchange. |
| `upstream_request_header` | string | no | unset | Same, read when the request leaves for the upstream. |
| `incoming_response_header` | string | no | unset | Same, read when the upstream response arrives. |
| `ext_proc_response_header` | string | no | unset | Same, read from the ext_proc response exchange. |
| `downstream_response_header` | string | no | unset | Same, read when the response is sent downstream. |
| `wasm_header` | string | no | unset | Same, read from WASM filter output. |
| `custom_operators` | list of strings | no | `[]` | Operator names usable in access-log format strings, filled from the captured JSON objects. |

```yaml,name=arion.yaml,arion=fragment
access_logging:
  blocking: false
  num_instances: 2
  queue_length: 4096
  log_rotation: daily
  max_log_files: 14
  incoming_request_header: x-arion-metadata
  custom_operators: [TENANT, PLAN]
```

## metrics

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `user_key` | object | no | unset | Partition key for user metrics: `source` is `!HeaderName <name>` or `Sni`, plus an optional `attribute_name`. |
| `custom_keys` | list | no | `[]` | Additional partition keys for custom metrics; each entry has `source: !HeaderName <name>` and optional `attribute_name`. |
| `rename` | map | no | `{}` | Renames emitted metrics, old name to new name. |
| `custom_metrics` | object | no | empty | Per-hook metric lists under `incoming_request`, `ext_proc_request`, `upstream_request`, `incoming_response`, `ext_proc_response`, `downstream_response` and `wasm`. Each entry is a `!Counter`, `!Gauge` or `!Histogram` with `name`, `description`, `header_name`, optional `attribute_name`, and `buckets` for histograms (numbers, or `MAX`). |

```yaml,name=arion.yaml,arion=fragment
metrics:
  user_key:
    source: !HeaderName x-user-id
    attribute_name: user
  custom_metrics:
    upstream_request:
      - !Counter
        name: api_requests
        description: Requests forwarded upstream
        header_name: x-api-key
        attribute_name: api_key
```

See the [metrics list](@/reference/observability/metrics-list.md) for what Arion emits.

## timezone

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `local` | string | yes | — | IANA timezone name, e.g. `Europe/Paris`. Empty or `UTC` keeps UTC. Daylight-saving transitions are tracked in the background. |

```yaml,name=arion.yaml,arion=fragment
timezone:
  local: Europe/Paris
```

## envoy_bootstrap

Contains a standard Envoy `Bootstrap`: `node`, `admin`, `static_resources` with `listeners`, `clusters` and `secrets`, and `dynamic_resources` for xDS. Field-level reference lives with each resource: [listeners](@/reference/resources/listeners.md), [routes](@/reference/resources/routes.md), [clusters](@/reference/resources/clusters.md), [secrets](@/reference/resources/secrets.md), and the [supported-configuration matrix](@/reference/envoy-compatibility/supported-configuration.md) for the full accepted subset.

```yaml,name=arion.yaml,arion=fragment
envoy_bootstrap:
  static_resources:
    listeners:
      - name: listener_http
        address:
          socket_address: { address: 0.0.0.0, port_value: 8080 }
        filter_chains:
          - name: default
            filters:
              - name: http
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  codec_type: HTTP1
                  http_filters:
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                  route_config:
                    name: main
                    virtual_hosts:
                      - name: backend
                        domains: ["*"]
                        routes:
                          - match: { prefix: "/" }
                            route: { cluster: api }
    clusters:
      - name: api
        type: STATIC
        connect_timeout: 0.25s
        lb_policy: ROUND_ROBIN
        load_assignment:
          endpoints:
            - lb_endpoints:
                - endpoint:
                    address:
                      socket_address: { address: 127.0.0.1, port_value: 5678 }
```

The `bootstrap` key accepts the same resources in Arion's native serialization; that form is documented only on the [native bootstrap](@/reference/configuration/native-bootstrap.md) page.

## Unknown and unsupported fields

- **Top level**: keys other than the seven above are ignored during deserialization.
- **Inside `envoy_bootstrap`**: parsing is strict. Unknown or misspelled field names fail to deserialize, and the error names the YAML path. Both protobuf snake_case (`filter_chains`) and JSON camelCase (`filterChains`) spellings are accepted.
- **Known Envoy fields that Arion does not implement** are refused at load with an `unsupported field` error rather than silently ignored — this is the [compatibility promise](@/docs/concepts/envoy-compatibility.md). A field marked unsupported only errors when it is actually set to a non-default value.
