For the complete documentation index, see llms.txt. This page is also available as Markdown.

Options

Detailed documentation of all configuration options available for mirrord, including usage, defaults, and examples.

accept_invalid_certificates

Controls whether or not mirrord accepts invalid TLS certificates (e.g. self-signed certificates).

If not provided, mirrord will use value from the kubeconfig.

agent

Configuration for the mirrord-agent pod that is spawned in the Kubernetes cluster.

Note: this configuration is ignored when using the mirrord Operator. Agent configuration is done by the cluster admin.

We provide sane defaults for this option, so you don't have to set up anything here.

{
  "agent": {
    "log_level": "info",
    "json_log": false,
    "namespace": "default",
    "image": "ghcr.io/metalbear-co/mirrord:latest",
    "image_pull_policy": "IfNotPresent",
    "image_pull_secrets": [ { "name": "secret" } ],
    "ttl": 30,
    "ephemeral": false,
    "communication_timeout": 30,
    "startup_timeout": 360,
    "flush_connections": false,
    "exclude_from_mesh": false
    "inject_headers": false,
    "override_cache_control": true,
    "max_body_buffer_size": 65535,
    "max_body_buffer_timeout": 1000,
    "http_detection_timeout": 2
  }
}

agent.annotations

Allows setting up custom annotations for the agent Job and Pod.

agent.check_out_of_pods

Determine if to check whether there is room for agent job in target node. (Not applicable when using ephemeral containers feature)

Can be disabled if the check takes too long and you are sure there is enough resources on each node

agent.clean_iptables_on_start

Clean leftover iptables rules and start the new agent instead of erroring out when there are existing mirrord rules in the target's iptables.

agent.communication_timeout

Controls how long the agent lives when there are no connections.

Each connection has its own heartbeat mechanism, so even if the local application has no messages, the agent stays alive until there are no more heartbeat messages.

agent.disable_mesh_sidecar_injection

Add relevant labels and annotations to agent pods/jobs to prevent service mesh sidecar injections. Defaults to true.

Only affects istio, linkerd, kuma.

agent.disabled_capabilities

If nothing is disabled here, agent uses:

  1. NET_ADMIN,

  2. SYS_PTRACE,

  3. SYS_ADMIN.

Has no effect when using the targetless mode, as targetless agent containers have no capabilities.

agent.dns

Configuration options for how the agent performs DNS resolution.

agent.dns.attempts

Specifies the number of DNS resolution attempts the agent will make before failing. Setting this too high may cause the internal proxy to time out and exit.

agent.dns.timeout

Specifies how long (in seconds) the agent will wait for a DNS response before timing out. If not specified the agent uses a default value of 1 second. Setting this too high may cause the internal proxy to time out and exit.

agent.ephemeral

Runs the agent as an ephemeral container.

Not compatible with targetless runs.

Defaults to false.

agent.exclude_from_mesh

When running the agent as an ephemeral container, use this option to exclude the agent's port from the service mesh sidecar proxy.

agent.external_ip_fix

Fixes passthrough requests failing when the target application listens on the pod's external IP instead of 127.0.0.1 (e.g. because it resolves its own pod name and binds to the pod IP).

When enabled, the agent passes redirected connections through to their original destination IP rather than to loopback. To avoid an iptables redirection loop, those connections are marked and excluded from the redirect rules; this requires SO_MARK support.

Enabled by default, set to false to pass redirected connections through to loopback.

agent.flush_connections

Flushes existing connections when starting to steal, might fix issues where connections aren't stolen (due to being already established)

Defaults to true.

agent.http_detection_timeout

How long, in seconds, to wait for data on a redirected connection during HTTP protocol detection before giving up and treating it as raw TCP. The timer resets on every read, so total detection time may exceed this value for connections that send data in many small chunks.

agent.image

Name of the agent's docker image.

Useful when a custom build of mirrord-agent is required, or when using an internal registry.

Defaults to the latest stable image "ghcr.io/metalbear-co/mirrord:latest".

Complete setup:

Can also be controlled via MIRRORD_AGENT_IMAGE, MIRRORD_AGENT_IMAGE_REGISTRY, and MIRRORD_AGENT_IMAGE_TAG. MIRRORD_AGENT_IMAGE takes precedence, followed by config values for registry/tag, then environment variables for registry/tag.

agent.image_pull_policy

Controls when a new agent image is downloaded.

Supports "IfNotPresent", "Always", "Never", or any valid kubernetes image pull policy

Defaults to "IfNotPresent"

agent.image_pull_secrets

List of secrets the agent pod has access to.

Takes an array of entries with the format { name: <secret-name> }.

Read more here.

agent.inject_headers

Sets whether Mirrord-Agent headers are injected into HTTP responses that went through the agent.

Possible values for the header:

  • passed-through: set when the request was not sent to the local app (perhaps because it didn't match the filters)

  • forwarded-to-client: set when the request was sent to the local app

agent.jaq_time_limit

Time limit for running jaq queries, in milliseconds. Defaults to 500ms.

agent.json_log

Controls whether the agent produces logs in a human-friendly format, or json.

agent.labels

Allows setting up custom labels for the agent Job and Pod.

agent.log_level

Log level for the agent.

Supports "trace", "debug", "info", "warn", "error", or any string that would work with RUST_LOG.

agent.max_body_buffer_size

Maximum size, in bytes, of HTTP request body buffers. Used for temporarily storing bodies of incoming HTTP requests to run body filters. HTTP body filters will not match any requests with bodies larger than this.

agent.max_body_buffer_timeout

Maximum timeout, in milliseconds, for receiving HTTP request bodies. HTTP body filters will not match any requests whose bodies do not arrive within this timeout.

agent.metrics

Enables prometheus metrics for the agent pod.

You might need to add annotations to the agent pod depending on how prometheus is configured to scrape for metrics.

agent.namespace

Namespace where the agent shall live.

Note: ignored in targetless runs or when the agent is run as an ephemeral container.

Defaults to the current kubernetes namespace.

agent.nftables

Determines which iptables backend will be used for traffic redirection.

If set to true, the agent will use iptables-nft. If set to false, the agent will use iptables-legacy. If not set, the agent will try to detect the correct backend at runtime.

agent.node_selector

Allows setting up custom node selector for the agent Pod. Applies only to targetless runs, as targeted agent always runs on the same node as its target container.

agent.override_cache_control

Sets whether the Cache-Control header in HTTP responses that went through the agent is replaced with no-cache, no-store, must-revalidate.

Responses served while the target is redirected are not representative of the target's normal output, so caching them (in the browser, or in a CDN in front of the cluster) both serves stale data to other users and hides subsequent requests from the agent.

Set this to false to leave the original Cache-Control header untouched.

agent.priority_class

Specifies the priority class to assign to the agent pod.

In some cases, the agent pod may fail to schedule due to node resource constraints. Setting a priority class allows you to explicitly assign an existing priority class from your cluster to the agent pod, increasing its priority relative to other workloads.

agent.privileged

Run the mirror agent as privileged container. Defaults to false.

Might be needed in strict environments such as Bottlerocket.

Has no effect when using the targetless mode, as targetless agent containers are never privileged.

agent.resources

Set pod resource requirements. (not with ephemeral agents) Default is

agent.security_context

Agent pod security context (not with ephemeral agents). Support seccomp profile and app armor profile.

agent.service_account

Allows setting up custom Service Account for the agent Job and Pod.

agent.startup_timeout

Controls how long to wait for the agent to finish initialization.

If initialization takes longer than this value, mirrord exits.

Defaults to 60.

agent.tolerations

Set pod tolerations. (not with ephemeral agents).

Defaults to operator: Exists.

Set to an empty array to have no tolerations at all

agent.ttl

Controls how long the agent pod persists for after the agent exits (in seconds).

Can be useful for collecting logs.

Defaults to 1.

api

Enables the local session monitor API server.

When enabled, mirrord exposes a Unix socket at ~/.mirrord/sessions/<session-id>.sock with HTTP endpoints for observing session activity in real time.

Defaults to true.

baggage

OpenTelemetry (OTel) / W3C baggage propagator. This is used in HTTP requests sent to the operator to manually set values in the trace span, which can help when processing traces. See OTel docs

Only relevant for use with the operator. For more details, read the docs on monitoring.

ci

Configuration for mirrord for CI.

ci.output_dir

Path to a directory where mirrord ci will flush application's stdout and stderr.

Defaults to /tmp/mirrord/.

container

Unstable: mirrord container command specific config.

container.cli_extra_args

Any extra args to use when creating the sidecar mirrord-cli container.

This is useful when you want to use portforwarding, passing -p local:container won't work for main command but adding them here will work

container.cli_image

Tag of the mirrord-cli image you want to use.

Defaults to "ghcr.io/metalbear-co/mirrord-cli:<cli version>".

container.cli_image_lib_path

Path of the mirrord-layer lib inside the specified mirrord-cli image.

container.cli_prevent_cleanup

Don't add --rm to sidecar command to prevent cleanup.

container.cli_tls_path

When usingmirrord container with external_proxy TLS enabled (is enabled by default), you can specify the path where the certificate .pem file will be created, in the cli container.

Defaults to "/opt/mirrord/tls/mirrord-tls.pem".

container.host_gateway_detection

Connects the internal proxy sidecar to the external proxy through the container runtime's host-gateway mechanism, instead of dialing a detected host IP.

The sidecar container is started with --add-host mirrord-external-proxy:host-gateway, and the internal proxy connects to that hostname. The external proxy also binds all interfaces by default so it's reachable through the container runtime's gateway.

When enabled, container.override_host_ip and the WSL-specific auto-adjustment of external_proxy.host_ip are no longer needed and are ignored.

container.override_host_ip

Allows to override the IP address for the internal proxy to use when connecting to the host machine from within the container.

This should be useful if your host machine is exposed with a different IP address than the one bound as host.

  • If you're running inside WSL, and encountering problems, try setting external_proxy.host_ip to 0.0.0.0, and this to the internal container runtime address (for docker, this would be what host.docker.internal resolved to, which by default is 192.168.65.254). You can find this ip by resolving it from inside a running container, e.g. docker run --rm -it {image-with-nslookup} nslookup host.docker.internal

container.platform

Platform specification for the target container (e.g., "linux/amd64", "linux/arm64").

When specified, the target container will run with this platform, while the internal proxy container will still run on the native platform and contain both architectures (x64/arm64). The LD_PRELOAD will automatically use the correct architecture.

experimental

mirrord Experimental features. This shouldn't be used unless someone from MetalBear/mirrord tells you to.

experimental applev

Configuration for inspecting and modifying apple variables. macOS only.

experimental browser_extension_config

mirrord will open a URL for initiating mirrord browser extension to automatically inject HTTP header that matches the HTTP filter configured in feature.network.incoming.http_filter.header_filter.

experimental disable_reuseaddr

Disables the SO_REUSEADDR socket option on sockets that mirrord steals/mirrors. On macOS the application can use the same address many times but then we don't steal it correctly. This probably should be on by default but we want to gradually roll it out. https://github.com/metalbear-co/mirrord/issues/2819 This option applies only on macOS.

Defaults to true in OSS. Defaults to false in mfT.

experimental dlopen_cgo

Useful when the user's application loads a c-shared golang library dynamically.

Defaults to false.

experimental enable_exec_hooks_linux

Enables exec hooks on Linux. Enable Linux hooks can fix issues when the application shares sockets with child commands (e.g Python web servers with reload), but the feature is not stable and may cause other issues.

experimental go_asmcgocall

On x86-64, route the Go 1.25+ syscall hook through the Go runtime's own runtime.asmcgocall for the switch to and from the g0 system stack, instead of the hand-rolled assembly switch. This mirrors what the arm64 hook already does and avoids corrupting the scheduler state (g.sched) of goroutines blocked in a syscall, which can crash cgo-heavy Go programs. No effect on arm64, which always uses runtime.asmcgocall.

Defaults to true in OSS. Defaults to false in mfT.

experimental guard_std_fds

Ensures the standard fds (0-2) are open when the layer initializes, pointing any closed one at /dev/null. Protects the layer's internal fds (most importantly its connection to the internal proxy) from being assigned a std fd number and reconfigured by the application's runtime, e.g. libuv setting O_NONBLOCK on what it considers stdin. https://github.com/metalbear-co/mirrord/issues/4622

DEPRECATED, WILL BE REMOVED

experimental hide_ipv6_interfaces

Enables getifaddrs hook that removes IPv6 interfaces from the list returned by libc.

experimental idle_local_http_connection_timeout

Sets a timeout for idle local HTTP connections (in milliseconds).

HTTP requests stolen with a filter are delivered to the local application from a HTTP connection made from the local machine. Once a request is delivered, the connection is cached for some time, so that it can be reused to deliver the next request.

This timeout determines for how long such connections are cached.

Set to 0 to disable caching local HTTP connections (connections will be dropped as soon as the request is delivered).

Defaults to 3000ms.

experimental ignore_system_proxy_config

Disables any system wide proxy configuration for affecting the running application.

experimental latency

Configuration for adding artificial latency to outgoing network operations.

DEPRECATED, WILL BE REMOVED Please use the mirrord chaos feature instead.

Configuration for adding artificial latency to outgoing network operations. Useful for testing application behavior under network delay conditions.

experimental latency.receive_delay

Delay in milliseconds for outgoing receive operations (Agent → Layer).

Defaults to 0 (no delay).

experimental latency.transmit_delay

Delay in milliseconds for outgoing send operations (Layer → Agent).

Defaults to 0 (no delay).

_experimental_non_blocking_tcp_connect

Enables better support for outgoing connections using non-blocking TCP sockets.

Due to technical reasons, enabling this causes the existence of the internal proxy acting as a TCP proxy observable to the application. Notable consequences of this include:

  1. getsockname(2) will always return a localhost address,

  2. connect(2) will succeed immediately, before the remote side of the connection is established. If the remote side of the connection fails, the connection to the app will be closed after the fact.

Essentially your application has to assume that it might be sitting behind a TCP proxy. Most "standard" apps (e.g. HTTP clients) should be unaffected, but custom implementations of other protocols may not.

DEPRECATED, WILL BE REMOVED

experimental sip_log_destination

Writes basic fork-safe SIP patching logs to a destination file. Useful for seeing the state of SIP when stdout may be affected by another process.

experimental sip_utils

Extract pre-built SIP utility binaries into ~/.mirrord/binaries on macOS and uses them in place of SIP-patching the originals. This shouldn't be used unless someone from MetalBear/mirrord tells you to.

DEPRECATED, WILL BE REMOVED

experimental tcp_ping4_mock

experimental trust_any_certificate

Enables trusting any certificate on macOS, useful for https://github.com/golang/go/issues/51991#issuecomment-2059588252

experimental use_dev_null

Uses /dev/null for creating local fake files (should be better than using /tmp)

external_proxy

Configuration for the external proxy mirrord spawns when using the mirrord container command. This proxy is used to allow the internal proxy running in sidecar to connect to the mirrord agent.

If you get ConnectionRefused errors, increasing the timeouts a bit might solve the issue.

external_proxy.host_ip

Specify a custom host ip addr to listen on.

This address must be accessible from within the container. If not specified, mirrord will try and resolve a local address to use.

  • If you're running inside WSL, and encountering problems, try setting this to 0.0.0.0, and container.override_host_ip to the internal container runtime address (for docker, this would be what host.docker.internal resolved to, which by default is 192.168.65.254).

external_proxy.idle_timeout

How much time to wait while we don't have any active connections before exiting.

Common cases would be running a chain of processes that skip using the layer and don't connect to the proxy.

external_proxy.json_log

Whether the proxy should output logs in JSON format. If false, logs are output in human-readable format.

Defaults to true.

external_proxy.log_destination

Set the log destination for the external proxy.

  1. If the provided path ends with a separator (/ on UNIX, \ on Windows), it will be treated as a path to directory where the log file should be created.

  2. Otherwise, if the path exists, mirrord will check if it's a directory or not.

  3. Otherwise, it will be treated as a path to the log file.

mirrord will auto create all parent directories.

Defaults to a randomized path inside the temporary directory.

external_proxy.log_level

Set the log level for the external proxy.

The value should follow the RUST_LOG convention (i.e mirrord=trace).

Defaults to mirrord=info,warn.

external_proxy.start_idle_timeout

How much time to wait for the first connection to the external proxy in seconds.

Common cases would be running with dlv or any other debugger, which sets a breakpoint on process execution, delaying the layer startup and connection to the external proxy.

feature

Controls mirrord features.

See the technical reference, Technical Reference to learn more about what each feature does.

The env, fs and network options have support for a shortened version, that you can see here.

feature.copy_target

Creates a new copy of the target. mirrord will use this copy instead of the original target (e.g. intercept network traffic). This feature requires a mirrord operator.

This feature is not compatible with rollout targets and running without a target (targetless mode).

Generated configuration for copy target feature.

feature.copy_target.exclude_containers

Set a list of containers to be ignored by copy_target

feature.copy_target.exclude_init_containers

Set a list of init containers to be ignored by copy_target

feature.copy_target.scale_down

If this option is set, mirrord will scale down the target deployment to 0 for the time the copied pod is alive.

This option is compatible only with deployment targets.

feature.db_branches

Configuration for the database branching feature.

The branch databases a session runs with. Either defined here, or taken from the dbBranches entries a cluster admin put on the target's MirrordSplitConfig, so mirrord exec and mirrord up use one definition that does not drift.

Inline, using a connection URL:

Inline, using individual connection params:

Every dbBranches entry of the target's MirrordSplitConfig:

Only the entries with these ids:

With "*" or a list of ids the operator resolves the entries, and sessions started under the same key that point at the same entry share one branch (its id is the entry id plus the key). An id that matches no entry fails the session, naming the ids the workload has; a workload with no dbBranches gives no branches and the session continues. An operator that cannot resolve entries fails the session before it starts. Inline definitions always win: with them, any dbBranches on the workload are ignored with a warning.

"*" or a list of entry ids, resolved by the operator against the target's MirrordSplitConfig.

Branches defined in this config.

Configuration for a database branch.

Example:

The fields below are shared by every engine. Not every engine has every one of them: an engine that mirrord does not spawn as a pod in the cluster takes no image/version, and one that is not reached over a connection to a server hosting many databases takes no name and locates its source its own way. Engine-specific fields (copy modes, iam_auth, connection_settings, emulator_host) are documented under each type.

feature.db_branches[].id (type: mysql, mariadb, pg, mongodb, mssql, redis)

Users can choose to specify a unique id. This is useful for reusing or sharing the same database branch among Kubernetes users.

feature.db_branches[].name (type: mysql, mariadb, pg, mongodb, mssql, redis)

When source database connection detail is not accessible to mirrord operator, users can specify the database name so it is included in the connection options mirrord uses as the override.

feature.db_branches[].ttl_secs (type: mysql, mariadb, pg, mongodb, mssql, redis)

Mirrord operator starts counting the TTL when a branch is no longer used by any session. The time-to-live (TTL) for the branch database is set to 300 seconds by default. Users can set ttl_secs to customize this value according to their need. Please note that longer TTL paired with frequent mirrord session turnover can result in increased resource usage. For this reason, branch database TTL caps out at 15 min.

Mutually exclusive with ttl_mins.

feature.db_branches[].ttl_mins (type: mysql, mariadb, pg, mongodb, mssql, redis)

Same as ttl_secs but expressed in minutes.

Mutually exclusive with ttl_secs.

feature.db_branches[].creation_timeout_secs (type: mysql, mariadb, pg, mongodb, mssql, redis)

The timeout in seconds to wait for a database branch to become ready after creation. Defaults to 60 seconds. Adjust this value based on your database size and cluster performance.

feature.db_branches[].version (type: mysql, mariadb, pg, mongodb, mssql, redis)

Mirrord operator uses a default version of the database image unless version is given.

Mutually exclusive with image.

feature.db_branches[].image (type: mysql, mariadb, pg, mongodb, mssql, redis)

Full image reference for the branch database container, including the tag (e.g. registry.example.com/postgresql:15-partman). Setting image overrides both the operator's built-in default image and any registry configured cluster-wide by the operator admin. Cluster admins can restrict which images are accepted with the per-database dbPod.allowedImages list in the operator's Helm values; when that list is not set, any image is allowed.

Mutually exclusive with version, as the image reference already carries the tag.

feature.db_branches[].profile (type: clickhouse, cockroachdb, dynamodb, generic, mariadb, mongodb, mssql, mysql, pg, redis, s3, spanner)

Name of an operator branch-config profile to use for this branch. Cluster admins can define named profiles under the per-database profiles map in the operator's Helm values (e.g. redisBranchConfig.profiles), each carrying its own pod settings such as TLS mode, server arguments, pull secrets, and allowed images. When profile is not set, the operator's default branch config applies. Referencing a profile the operator does not define fails the branch with an error listing the available profiles.

feature.db_branches[].connection (type: mysql, mariadb, pg, mongodb, mssql, redis)

connection describes how to get the connection information to the source database. When the branch database is ready for use, Mirrord operator will replace the connection information with the branch database's. It accepts a connection URL or individual params:

Any param can also be read from a Kubernetes Secret instead of a target-pod env var:

Or from a Kubernetes ConfigMap, for apps whose connection details live in a mounted config file. configmap is the ConfigMap's name, or { "volume": "<name>" } to follow a configMap volume of the target pod (this keeps working when the ConfigMap is renamed per release). key is the data key; value_selector (a .a.b path into the JSON/YAML entry) or value_pattern (a regex over the raw text) picks the value out of it; env_var_name hands the branch's value to the local app under that name:

When the operator's branch config (or the branch's profile) sets dbPod.sourceConfigMap, configmap and key may be omitted and are filled from there, so a param is just its selector: { "value_selector": ".database.host", "env_var_name": "DB_HOST" }. A param with only value_pattern and env_var_name is the env var pattern source instead, so a pattern against the profile's ConfigMap keeps key. ConfigMap sources need operator 3.204.0 and mirrord 3.255.0 or later.

feature.db_branches[].migrations (type: mysql, mariadb, pg, mssql, clickhouse)

Schema migrations to run on the branch after it is created. The flavor field selects how they run.

Flyway with a local migrations directory:

  • path: local directory holding the migration files, resolved relative to the working directory.

  • image: optional container image override for the migration runner.

Flyway with the SQL baked into the job image, running against in-image paths:

  • locations: Flyway locations inside image holding the migration files. Mutually exclusive with path, and requires image.

Liquibase with a local changelog directory:

  • path: local directory holding the changelog files, resolved relative to the working directory.

  • changelog_file: root changelog file, relative to path.

  • image: optional container image override for the migration runner.

Liquibase with the changelogs baked into the job image, running against in-image paths:

  • search_path: Liquibase search path inside image. Mutually exclusive with path, and requires image.

changelog_file is resolved inside the search root - a leading / is accepted and normalised to the same name - and is recorded in DATABASECHANGELOG, so changing it re-runs every changeset.

A user-provided image and command, for apps that ship migrations in their own image (e.g. a setup script that runs the framework's migration command):

  • image: full image reference for the migration container, including the tag.

  • command/args: optional entrypoint overrides; when unset, the image's own entrypoint runs.

  • env: extra environment variables. The operator injects the branch connection as MIRRORD_DB_HOST, MIRRORD_DB_PORT, MIRRORD_DB_USER, MIRRORD_DB_PASSWORD, and MIRRORD_DB_NAME; env values (and command/args) can reference them with Kubernetes $(VAR) expansion.

Requires name to be set.

When configuring a branch for ClickHouse, set type to clickhouse.

Users can choose from the following copy mode to bootstrap their ClickHouse branch database:

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • Schema

    Creates an empty database and copies the schema of all tables.

  • All

    Copies both schema and data of all tables. This option shall only be used when the data volume of the source database is minimal.

In empty and schema mode, a per-table filter (a ClickHouse WHERE clause) copies just the matching rows of the listed tables.

When configuring a branch for CockroachDB, set type to cockroachdb.

CockroachDB is PostgreSQL-wire-compatible, so the app connects to the branch with its existing PostgreSQL driver. The branch itself is a cockroachdb/cockroach single node and the copy uses CockroachDB-native tooling (cockroach sql, SHOW CREATE ALL TABLES, COPY ... TO/FROM STDOUT/STDIN WITH CSV) rather than the PostgreSQL dump tools.

Users can choose from the following copy mode to bootstrap their CockroachDB branch database:

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • Schema

    Creates an empty database and copies schema of all tables via SHOW CREATE ALL TABLES.

  • All

    Copies both schema and data of all tables. This option shall only be used when the data volume of the source database is minimal.

When configuring a branch for DynamoDB, set type to dynamodb.

Users can choose from the following copy mode to bootstrap their DynamoDB branch database:

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • All

    Copies both schema and data of all collections. Supports optional collection filters to copy only specific collections or filter documents within collections.

feature.db_branches[].iam_auth (type: dynamodb)

AWS IAM credentials used to read the source DynamoDB tables. DynamoDB has no password-based connection mode, so this is the only way to authenticate against the source when copy.mode is all.

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

Environment variable sources follow the same pattern as connection.url:

  • { "type": "env", "variable": "VAR_NAME" } - direct env var from pod spec

  • { "type": "env_from", "variable": "VAR_NAME" } - from configMapRef/secretRef

For AWS RDS/Aurora IAM authentication, set type to "aws_rds".

Credentials for signing the RDS auth token come from one of two setups:

  • Static keys: the operator copies AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN from the target pod's environment (or from the env vars named in the fields below) to the branch pod.

  • IRSA / EKS Pod Identity: when the target pod has no static keys, the branch pod runs under the target's service account and receives the same IAM role. No key fields are needed; { "type": "aws_rds" } is enough.

Example with explicit env var sources:

Parameters:

  • region: AWS region. If not specified, uses AWS_REGION or AWS_DEFAULT_REGION from the target pod. With IRSA, set it explicitly if neither var is in the target's pod spec.

  • access_key_id: AWS Access Key ID. If not specified, uses AWS_ACCESS_KEY_ID.

  • secret_access_key: AWS Secret Access Key. If not specified, uses AWS_SECRET_ACCESS_KEY.

  • session_token: AWS Session Token (for temporary credentials). If not specified, uses AWS_SESSION_TOKEN.

For GCP Cloud SQL IAM authentication, set type to "gcp_cloud_sql".

Example for GCP Cloud SQL with credentials from a secret:

The init container must have GCP credentials (via Workload Identity or service account key). Use either credentials_json OR credentials_path, not both.

Parameters:

  • credentials_json: Inline service account JSON key content. Specify the env var that contains the raw JSON content of the service account key. Example: { "type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS_JSON" }.

  • credentials_path: Path to service account JSON key file. Specify the env var that contains the file path to the service account key. The file must be accessible from the init container. Example: {"type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS"}.

  • project: GCP project ID. If not specified, uses GOOGLE_CLOUD_PROJECT or GCP_PROJECT.

When branching a database, cache, or any other stateful service that mirrord has no built-in engine for, set type to generic.

A generic branch runs the container image you supply, starting empty - there are no built-in copy modes, IAM auth, or schema handling. The operator resolves each parameter you declare under connection.params from the target pod and injects it into the branch container as an env var named MIRRORD_PARAM_<NAME> (a Secret-backed param arrives as a secretKeyRef; the operator never reads its value). Reference these in command, args, and env with Kubernetes' native $(VAR) syntax so the branch bootstraps itself with the same values the app already uses. mirrord then only redirects the app's host/port vars to the branch - everything else in the app's environment keeps working unchanged.

To fill the branch with schema and data, supply a copy Job (below) - your own image that copies from the source into the branch. The branch only turns Ready once the Job succeeds.

Two built-ins are always available alongside the params: MIRRORD_BRANCH_ID and, when the shared name field is set, MIRRORD_DATABASE_NAME.

feature.db_branches[].image (type: generic)

Full image reference for the branch container, including the tag (e.g. docker.io/library/influxdb:2.7). This is the shared image field, but unlike the built-in engines a generic branch has no default image, so it is required - unless the shared profile field is set and the admin's profile supplies the image (the operator fails the branch if neither does). The shared version field is not allowed for generic branches - the tag lives here.

feature.db_branches[].port (type: generic)

The port the branched service listens on. Used as the default readiness probe target and as the port the app's connection is redirected to. Required, unless the shared profile field is set and the admin's profile supplies the port.

feature.db_branches[].copy (type: generic)

A one-shot Kubernetes Job that copies schema and data from the source into the branch, using an image you author. It runs after the branch container turns ready, and the branch only becomes usable once the Job exits successfully. The Job's environment carries the same MIRRORD_PARAM_<NAME> vars as the branch container (the source connection), plus MIRRORD_BRANCH_HOST and MIRRORD_BRANCH_PORT (where to write). What to copy (full/schema-only/filtered) is entirely up to the image's own command.

The copy runs at most once per branch: reusing a Ready branch (by id) never re-runs it, even if the copy config changed - use a new id for a fresh copy.

When the shared profile field is set, the admin's profile can supply the copy Job instead (dbPod.copy in the operator's generic branch config); a copy here wins over the profile's.

feature.db_branches[].command / args (type: generic)

Optional entrypoint override for the branch container. Values may reference declared params with $(MIRRORD_PARAM_<NAME>); use $$(...) for a literal $(...). Values written directly into args are visible in the pod spec - reference params via $(VAR) instead of inlining secrets.

feature.db_branches[].env (type: generic)

Extra environment variables for the branch container. Values support the same $(MIRRORD_PARAM_<NAME>) references as command/args. Keys must not start with MIRRORD_PARAM_ or collide with the built-ins.

feature.db_branches[].readiness (type: generic)

Readiness check for the branch container. Defaults to a TCP probe on port.

Example - an empty InfluxDB branch, bootstrapped with the app's own token/org/bucket so the app's untouched credential vars stay valid against the branch:

token, org, and bucket are custom params - any key works under connection.params, not just the fixed host/port/user/password/database slots. The connection must use params mode (URL-shaped env vars are covered by value_pattern on host/port), and gcp_secret_manager/aws_secrets_manager sources are not supported for generic branches.

Entrypoint args override for the branch container.

Entrypoint command override for the branch container.

One-shot Job that copies schema/data from the source into the branch before it turns Ready.

Extra environment variables for the branch container.

The port the branched service listens on. Required unless profile is set and the profile supplies it.

Readiness check for the branch container. Defaults to a TCP probe on port.

When configuring a branch for MariaDB, set type to mariadb.

MariaDB branches use MariaDB-native tooling (mariadb-dump / mariadb-admin) and a MariaDB 12 branch image, so MariaDB-only objects such as sequences and system-versioned (temporal) tables are copied correctly - which a MySQL dump/image mishandles.

Users can choose from the following copy mode to bootstrap their MariaDB branch database.

All copy modes accept dump_args, passed to mariadb-dump as-is, which can leave out what the copy mode copies, such as stored routines with --skip-routines.

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • Schema

    Creates an empty database and copies schema of all tables.

  • All

    Copies both schema and data of all tables. This option shall only be used when the data volume of the source database is minimal.

feature.db_branches[].iam_auth (type: mariadb)

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

Environment variable sources follow the same pattern as connection.url:

  • { "type": "env", "variable": "VAR_NAME" } - direct env var from pod spec

  • { "type": "env_from", "variable": "VAR_NAME" } - from configMapRef/secretRef

For AWS RDS/Aurora IAM authentication, set type to "aws_rds".

Credentials for signing the RDS auth token come from one of two setups:

  • Static keys: the operator copies AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN from the target pod's environment (or from the env vars named in the fields below) to the branch pod.

  • IRSA / EKS Pod Identity: when the target pod has no static keys, the branch pod runs under the target's service account and receives the same IAM role. No key fields are needed; { "type": "aws_rds" } is enough.

Example with explicit env var sources:

Parameters:

  • region: AWS region. If not specified, uses AWS_REGION or AWS_DEFAULT_REGION from the target pod. With IRSA, set it explicitly if neither var is in the target's pod spec.

  • access_key_id: AWS Access Key ID. If not specified, uses AWS_ACCESS_KEY_ID.

  • secret_access_key: AWS Secret Access Key. If not specified, uses AWS_SECRET_ACCESS_KEY.

  • session_token: AWS Session Token (for temporary credentials). If not specified, uses AWS_SESSION_TOKEN.

For GCP Cloud SQL IAM authentication, set type to "gcp_cloud_sql".

Example for GCP Cloud SQL with credentials from a secret:

The init container must have GCP credentials (via Workload Identity or service account key). Use either credentials_json OR credentials_path, not both.

Parameters:

  • credentials_json: Inline service account JSON key content. Specify the env var that contains the raw JSON content of the service account key. Example: { "type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS_JSON" }.

  • credentials_path: Path to service account JSON key file. Specify the env var that contains the file path to the service account key. The file must be accessible from the init container. Example: {"type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS"}.

  • project: GCP project ID. If not specified, uses GOOGLE_CLOUD_PROJECT or GCP_PROJECT.

When configuring a branch for MongoDB, set type to mongodb.

Users can choose from the following copy mode to bootstrap their MongoDB branch database:

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • All

    Copies both schema and data of all collections. Supports optional collection filters to copy only specific collections or filter documents within collections.

feature.db_branches[].iam_auth (type: mongodb)

IAM authentication for the source database. Use this when your source database (e.g. MongoDB Atlas with AWS IAM) requires the MONGODB-AWS authentication mechanism instead of password-based authentication. Only the aws_rds type is supported for MongoDB.

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

Environment variable sources follow the same pattern as connection.url:

  • { "type": "env", "variable": "VAR_NAME" } - direct env var from pod spec

  • { "type": "env_from", "variable": "VAR_NAME" } - from configMapRef/secretRef

For AWS RDS/Aurora IAM authentication, set type to "aws_rds".

Credentials for signing the RDS auth token come from one of two setups:

  • Static keys: the operator copies AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN from the target pod's environment (or from the env vars named in the fields below) to the branch pod.

  • IRSA / EKS Pod Identity: when the target pod has no static keys, the branch pod runs under the target's service account and receives the same IAM role. No key fields are needed; { "type": "aws_rds" } is enough.

Example with explicit env var sources:

Parameters:

  • region: AWS region. If not specified, uses AWS_REGION or AWS_DEFAULT_REGION from the target pod. With IRSA, set it explicitly if neither var is in the target's pod spec.

  • access_key_id: AWS Access Key ID. If not specified, uses AWS_ACCESS_KEY_ID.

  • secret_access_key: AWS Secret Access Key. If not specified, uses AWS_SECRET_ACCESS_KEY.

  • session_token: AWS Session Token (for temporary credentials). If not specified, uses AWS_SESSION_TOKEN.

For GCP Cloud SQL IAM authentication, set type to "gcp_cloud_sql".

Example for GCP Cloud SQL with credentials from a secret:

The init container must have GCP credentials (via Workload Identity or service account key). Use either credentials_json OR credentials_path, not both.

Parameters:

  • credentials_json: Inline service account JSON key content. Specify the env var that contains the raw JSON content of the service account key. Example: { "type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS_JSON" }.

  • credentials_path: Path to service account JSON key file. Specify the env var that contains the file path to the service account key. The file must be accessible from the init container. Example: {"type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS"}.

  • project: GCP project ID. If not specified, uses GOOGLE_CLOUD_PROJECT or GCP_PROJECT.

When configuring a branch for MSSQL, set type to mssql.

Users can choose from the following copy mode to bootstrap their MSSQL branch database:

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • Schema

    Creates an empty database and copies schema of all tables.

  • All

    Copies both schema and data of all tables. This option shall only be used when the data volume of the source database is minimal.

When configuring a branch for MySQL, set type to mysql.

Users can choose from the following copy mode to bootstrap their MySQL branch database.

All copy modes accept dump_args, passed to mysqldump as-is, which can leave out what the copy mode copies, such as stored routines with --skip-routines.

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • Schema

    Creates an empty database and copies schema of all tables.

  • All

    Copies both schema and data of all tables. This option shall only be used when the data volume of the source database is minimal.

feature.db_branches[].iam_auth (type: mysql)

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

Environment variable sources follow the same pattern as connection.url:

  • { "type": "env", "variable": "VAR_NAME" } - direct env var from pod spec

  • { "type": "env_from", "variable": "VAR_NAME" } - from configMapRef/secretRef

For AWS RDS/Aurora IAM authentication, set type to "aws_rds".

Credentials for signing the RDS auth token come from one of two setups:

  • Static keys: the operator copies AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN from the target pod's environment (or from the env vars named in the fields below) to the branch pod.

  • IRSA / EKS Pod Identity: when the target pod has no static keys, the branch pod runs under the target's service account and receives the same IAM role. No key fields are needed; { "type": "aws_rds" } is enough.

Example with explicit env var sources:

Parameters:

  • region: AWS region. If not specified, uses AWS_REGION or AWS_DEFAULT_REGION from the target pod. With IRSA, set it explicitly if neither var is in the target's pod spec.

  • access_key_id: AWS Access Key ID. If not specified, uses AWS_ACCESS_KEY_ID.

  • secret_access_key: AWS Secret Access Key. If not specified, uses AWS_SECRET_ACCESS_KEY.

  • session_token: AWS Session Token (for temporary credentials). If not specified, uses AWS_SESSION_TOKEN.

For GCP Cloud SQL IAM authentication, set type to "gcp_cloud_sql".

Example for GCP Cloud SQL with credentials from a secret:

The init container must have GCP credentials (via Workload Identity or service account key). Use either credentials_json OR credentials_path, not both.

Parameters:

  • credentials_json: Inline service account JSON key content. Specify the env var that contains the raw JSON content of the service account key. Example: { "type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS_JSON" }.

  • credentials_path: Path to service account JSON key file. Specify the env var that contains the file path to the service account key. The file must be accessible from the init container. Example: {"type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS"}.

  • project: GCP project ID. If not specified, uses GOOGLE_CLOUD_PROJECT or GCP_PROJECT.

When configuring a branch for PostgreSQL, set type to pg.

feature.db_branches[].additional_databases (type: pg)

More databases from the same source server, copied into the same branch server. Use it when your application talks to several databases on one PostgreSQL server: every database lands on one branch pod, so the application keeps using a single host.

Each entry is dumped with the source connection of this branch (same host, port, user, password, TLS, iam_auth and connection_settings); only the database name differs. The database gets the same name on the branch.

  • name: the database name on the source server. Must differ from the branch's own database and from every other entry.

  • connection (optional): how the application reaches this database, in the same shape as connection. mirrord points it at the branch with this database's name. Without it, the database is only created and copied, and the application switches to it on the branch host by itself.

  • copy (optional): copy mode and table filters for this database, in the same shape as the branch's own copy. Defaults to empty.

feature.db_branches[].connection_settings (type: pg)

PostgreSQL settings (GUCs) applied to every source connection mirrord opens while building the branch. Each entry is sent at connection startup via PGOPTIONS, so it is in effect before any schema dump or data copy runs.

The common use is a Row-Level Security tenant variable: if a source table has an RLS policy that reads current_setting('my.tenant'), set { "my.tenant": "1234" } here so the copy can read the rows. Other GUCs work too, e.g. role to assume a table owner, or search_path.

Values are literal strings; the usual config templating (such as {{ get_env(...) }}) still applies before they are sent.

Users can choose from the following copy mode to bootstrap their PostgreSQL branch database.

All copy modes accept dump_args. When this field is set, it replaces the default pg_dump arguments. The defaults are --no-owner and --no-acl; include them explicitly when overriding if you want to preserve the default behavior. An empty list means no dump args.

  • Empty

    Creates an empty database. If the source DB connection options are found from the chosen target, mirrord operator extracts the database name and create an empty DB. Otherwise, mirrord operator looks for the name field from the branch DB config object. This option is useful for users that run DB migrations themselves before starting the application.

  • Schema

    Creates an empty database and copies schema of all tables.

  • All

    Copies both schema and data of all tables. This option shall only be used when the data volume of the source database is minimal.

feature.db_branches[].iam_auth (type: pg)

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

IAM authentication for the source database. Use this when your source database (AWS RDS, GCP Cloud SQL) requires IAM authentication instead of password-based authentication.

Environment variable sources follow the same pattern as connection.url:

  • { "type": "env", "variable": "VAR_NAME" } - direct env var from pod spec

  • { "type": "env_from", "variable": "VAR_NAME" } - from configMapRef/secretRef

For AWS RDS/Aurora IAM authentication, set type to "aws_rds".

Credentials for signing the RDS auth token come from one of two setups:

  • Static keys: the operator copies AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN from the target pod's environment (or from the env vars named in the fields below) to the branch pod.

  • IRSA / EKS Pod Identity: when the target pod has no static keys, the branch pod runs under the target's service account and receives the same IAM role. No key fields are needed; { "type": "aws_rds" } is enough.

Example with explicit env var sources:

Parameters:

  • region: AWS region. If not specified, uses AWS_REGION or AWS_DEFAULT_REGION from the target pod. With IRSA, set it explicitly if neither var is in the target's pod spec.

  • access_key_id: AWS Access Key ID. If not specified, uses AWS_ACCESS_KEY_ID.

  • secret_access_key: AWS Secret Access Key. If not specified, uses AWS_SECRET_ACCESS_KEY.

  • session_token: AWS Session Token (for temporary credentials). If not specified, uses AWS_SESSION_TOKEN.

For GCP Cloud SQL IAM authentication, set type to "gcp_cloud_sql".

Example for GCP Cloud SQL with credentials from a secret:

The init container must have GCP credentials (via Workload Identity or service account key). Use either credentials_json OR credentials_path, not both.

Parameters:

  • credentials_json: Inline service account JSON key content. Specify the env var that contains the raw JSON content of the service account key. Example: { "type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS_JSON" }.

  • credentials_path: Path to service account JSON key file. Specify the env var that contains the file path to the service account key. The file must be accessible from the init container. Example: {"type": "env", "variable": "GOOGLE_APPLICATION_CREDENTIALS"}.

  • project: GCP project ID. If not specified, uses GOOGLE_CLOUD_PROJECT or GCP_PROJECT.

feature.db_branches[].query_params (type: pg)

Query parameters applied to the branch connection handed to your application - the reconstructed connection URL and, in params mode, the matching environment variables. Values win over mirrord's own defaults. They only affect the branch connection; the source database connection used for the copy is not changed.

The common use is sslmode: a source like GCP Cloud SQL may require ?sslmode=require, while the branch pod mirrord creates serves no TLS, so the branch connection needs { "sslmode": "disable" } (this is also mirrord's default for non-TLS branch pods).

When configuring a branch for Redis, set type to redis.

Configuration for a local Redis branch.

Example with URL-based connection:

Example with separated settings:

feature.db_branches[].connection (type: redis)

Connection configuration for the Redis instance.

Supports either a complete URL or separated connection parameters. If both are provided, url takes precedence.

The following fields can be sourced via remote environment variable:

  • url

  • host

  • password

  • username

Example:

feature.db_branches[].connection.database (type: redis)

Redis database number (default: 0).

feature.db_branches[].connection.host (type: redis)

Redis host/hostname. Can be sourced from an environment variable.

feature.db_branches[].connection.password (type: redis)

Redis password for authentication. Can be sourced from an environment variable.

feature.db_branches[].connection.port (type: redis)

Redis port (default: 6379).

feature.db_branches[].connection.tls (type: redis)

Enable TLS/SSL connection.

feature.db_branches[].connection.url (type: redis)

Complete Redis URL (e.g., redis://user:pass@host:6379/0). Can be sourced from an environment variable.

feature.db_branches[].connection.username (type: redis)

Redis username (Redis 6+ ACL). Can be sourced from an environment variable.

feature.db_branches[].id (type: redis)

Optional unique identifier for reusing branches across sessions.

feature.db_branches[].local (type: redis)

Local Redis runtime configuration.

Configuration for local Redis runtime.

feature.db_branches[].local.container_command (type: redis)

Custom path to the container command. If not provided, uses the runtime name from PATH (e.g., "docker"). Example: /usr/local/bin/docker or /home/user/.local/bin/podman

feature.db_branches[].local.container_runtime (type: redis)

Which container runtime to use (Docker, Podman, or nerdctl). Only applies when runtime is container or auto.

Container runtimes supported by mirrord.

Docker container runtime. (default)

nerdctl container runtime (containerd).

Podman container runtime.

feature.db_branches[].local.options (type: redis)

Additional Redis configuration options.

Example:

Raw arguments passed directly to redis-server or as Docker CMD args. Use standard Redis config syntax (e.g., "--maxmemory 256mb").

feature.db_branches[].local.port (type: redis)

Local port to bind Redis to (default: 6379).

feature.db_branches[].local.runtime (type: redis)

Runtime backend for local Redis: container, redis_server, or auto.

For container-based runtimes, mirrord spawns the Redis image in a container. For redis_server, it runs the native binary directly.

Backends:

  • container (default) - Uses a container runtime (Docker/Podman/nerdctl), configured via container_runtime.

  • redis_server - Uses native redis-server binary

  • auto - Tries container first, falls back to redis-server

feature.db_branches[].local.server_command (type: redis)

Custom path to the redis-server binary. If not provided, uses "redis-server" from PATH. Example: /opt/redis/bin/redis-server

feature.db_branches[].local.version (type: redis)

Redis version/tag to use (default: "7-alpine"). Used as the container image tag.

Configuration for a remote Redis branch.

feature.db_branches[].copy (type: redis)

How a Redis branch is seeded from its source.

How a Redis branch is seeded from its source.

  • empty (default): Start a fresh, empty instance.

  • all: Copy keys from the source instance. Optional patterns are SCAN MATCH globs limiting which keys are copied; omitting them copies the whole keyspace.

When configuring a branch for an object storage bucket, set type to s3.

The branch bucket is created and seeded by the provider's own API, so - unlike the engines mirrord runs as database servers - an S3 branch has no pod in the cluster and takes no image nor version. It is otherwise a normal branch: the standard id, ttl_secs/ttl_mins, creation_timeout_secs and profile options all apply.

The source bucket is located with a bucket purum naming the env var on the target that holds the bucket name. Once the branch bucket exists, the operator points that same variable at it, so the app reads and writes the branch instead of the real bucket with no code change.

Example:

feature.db_branches[].copy (type: s3)

How the branch bucket is seeded from the source bucket.

Users can choose from the following copy modes to bootstrap their S3 branch bucket:

  • Empty (default)

    Creates the branch bucket with no objects in it. Useful for apps that write their own fixtures, or when the source bucket is far too large to clone.

  • All

    Copies the objects of the source bucket into the branch bucket. Optional objects field is a list of regular expressions matched against object keys, selecting the objects to be copied. Omitting this field or passing an empty list copies all objects.

The copy runs in the provider's cloud - mirrord never streams the objects through the cluster - so a wide all costs provider-side copy time rather than local bandwidth.

feature.db_branches[].provider (type: s3)

Cloud provider hosting the source bucket. Defaults to AWS.

Cloud provider hosting an S3 branch's source bucket.

Currently Amazon S3 is the only provider supported. This config option exists just for forward compatibility.

Amazon S3.

feature.db_branches[].source (type: s3)

Where to read the source bucket's name from, in the same params shape the other engines use for their connection details - type picks how the variables are resolved on the target (env for the pod spec's own env, env_from for its envFrom sources), and is auto-detected when omitted.

The single param an S3 branch takes is bucket:

Its value is as flexible as any other engine's params: a Kubernetes Secret ({ "secret": "my-secret", "key": "bucket" }), a literal ({ "variable": "MY_BUCKET_ENV_VAR", "value": "my-bucket" }), or a regex extracting the name out of a larger variable ({ "env_var_name": "S3_URI", "value_pattern": "..." }).

Connection parameters specified as individual environment variable names. The type field is optional - when omitted, the operator auto-detects whether the variable comes from env or envFrom on the target pod.

Individual database connection parameter sources. At least one parameter must be specified. Each parameter is either a plain string (env var name) or an object with secret and key.

Engine-specific connection parameters that have no universal slot above, keyed by a name the engine recognizes. They are written flat alongside the fixed slots, so a Spanner params block reads { "project": ..., "instance": ..., "database_id": ... } with no nesting. The operator resolves each from the target pod and hands it to the branch init sidecar. A param with a branch-side equivalent (PostgreSQL's and CockroachDB's sslmode, an S3 branch's bucket) also gets its env var rewritten on the local app to the branch's own value; the rest are read-only source locators the local app keeps untouched.

PostgreSQL and CockroachDB accept sslmode: the TLS mode of the source connection, which params mode has no URL to carry.

An S3 branch accepts bucket: the name of the source bucket, which the operator repoints at the branch bucket once that exists.

Google Cloud Spanner keys name the env vars on the target pod that hold its three separate source identifiers:

  • project: the GCP project id the source Spanner instance lives in.

  • instance: the source Spanner instance id within that project.

  • database_id: the source database id to recreate in the emulator (and, for the schema / all copy modes, copy schema and data from).

Spanner uses database_id rather than the fixed database slot above because the two mean different things. The fixed slot is an override target: the operator rewrites the app's database var to point at the branch's database. Spanner never rewrites it - the app keeps its own database id and is redirected wholesale by SPANNER_EMULATOR_HOST - so its database is a read-only locator the init sidecar uses to pick which source database to recreate, exactly like project and instance. The distinct name also keeps it from colliding with the flattened fixed database slot.

Unknown keys are rejected by the operator for the resolved engine.

The type of environment variable source for connection params.

When configuring a branch for Google Cloud Spanner, set type to spanner.

The branch runs the Cloud Spanner emulator. mirrord redirects the app to it by injecting SPANNER_EMULATOR_HOST, so the app's own project/instance/database values keep working and now resolve against the emulator. The branch init sidecar recreates the matching instance and database in the emulator and, for schema/all, copies from the real Spanner using the target pod's Google service account (Workload Identity / Application Default Credentials).

Spanner's source identifiers live flat under connection.params: project, instance, and database_id each name the env var (on the target pod) that holds the value. They are read only - the app never has them overridden - so they belong with the connection source rather than at the top level. database_id (not database) keeps the locator from colliding with the fixed database connection slot. emulator_host is the exception: it is the var mirrord sets on the local process to point at the branch, so it stays top-level.

Example:

Users can choose from the following copy mode to bootstrap their Spanner branch database:

  • Empty

    Creates an empty database. The instance and database matching the app's configuration are created in the emulator, but no schema or data is copied. Useful when the app runs its own migrations.

  • Schema

    Creates the database and copies the DDL (tables and indexes) of the source database.

  • All

    Copies both schema and data. Use only when the source data volume is minimal.

feature.db_branches[].emulator_host (type: spanner)

The name of the env var mirrord sets on your process to redirect it to the branch emulator - not an address. mirrord fills that var's value with the branch emulator's host:port at runtime; you only choose which variable it writes to.

Defaults to SPANNER_EMULATOR_HOST, the variable every official Spanner client library checks on its own, so the default redirects the app with no code change. Leave it unset unless your app ignores that built-in detection and reads the emulator endpoint from a differently-named variable (for example it reads MY_EMULATOR and passes that endpoint to the client explicitly); then set this to that variable's name so mirrord writes the address where your app actually looks.

When configuring a branch for a turbopuffer namespace, set type to turbopuffer.

The branch namespace is a copy-on-write clone made by turbopuffer itself, so - like an S3 branch - it has no pod in the cluster and takes no image nor version. It is otherwise a normal branch: the standard id, ttl_secs/ttl_mins and creation_timeout_secs options all apply.

turbopuffer clients pick the namespace per request, so the app has to read the namespace name from an env var for mirrord to redirect it. The namespace param names that var; once the branch exists, the operator points it at the branch namespace. The api_key param names where the operator reads the API key it branches with, and region (or base_url) where the namespace lives. Those two are only read, never rewritten.

Example:

feature.db_branches[].copy (type: turbopuffer)

How the branch namespace is seeded from the source namespace.

Users can choose from the following copy modes to bootstrap their turbopuffer branch:

  • Empty (default)

    Reserves a fresh namespace name with nothing in it; turbopuffer creates the namespace on the app's first write.

  • All

    Branches the source namespace: an instant copy-on-write clone with every document and the schema. Writes to either side never reach the other.

feature.db_branches[].source (type: turbopuffer)

Where to read the source namespace, the API key and the region from, in the same params shape the other engines use for their connection details - type picks how the variables are resolved on the target (env for the pod spec's own env, env_from for its envFrom sources), and is auto-detected when omitted.

The params a turbopuffer branch takes:

  • namespace (required): the env var holding the source namespace name. The operator rewrites it to the branch namespace, so it must name an env var.

  • api_key (required): the API key used to branch and later delete the namespace.

  • region: the turbopuffer region, e.g. gcp-us-central1.

  • base_url: the full API endpoint, for dedicated clusters. Exactly one of region and base_url must be set.

Each value is as flexible as any other engine's params: a Kubernetes Secret ({ "secret": "my-secret", "key": "namespace" }), a literal ({ "env_var_name": "TURBOPUFFER_REGION", "value": "gcp-us-central1" }), or a regex extracting the name out of a larger variable ({ "env_var_name": "TPUF_URI", "value_pattern": "..." }).

Connection parameters specified as individual environment variable names. The type field is optional - when omitted, the operator auto-detects whether the variable comes from env or envFrom on the target pod.

Individual database connection parameter sources. At least one parameter must be specified. Each parameter is either a plain string (env var name) or an object with secret and key.

Engine-specific connection parameters that have no universal slot above, keyed by a name the engine recognizes. They are written flat alongside the fixed slots, so a Spanner params block reads { "project": ..., "instance": ..., "database_id": ... } with no nesting. The operator resolves each from the target pod and hands it to the branch init sidecar. A param with a branch-side equivalent (PostgreSQL's and CockroachDB's sslmode, an S3 branch's bucket) also gets its env var rewritten on the local app to the branch's own value; the rest are read-only source locators the local app keeps untouched.

PostgreSQL and CockroachDB accept sslmode: the TLS mode of the source connection, which params mode has no URL to carry.

An S3 branch accepts bucket: the name of the source bucket, which the operator repoints at the branch bucket once that exists.

Google Cloud Spanner keys name the env vars on the target pod that hold its three separate source identifiers:

  • project: the GCP project id the source Spanner instance lives in.

  • instance: the source Spanner instance id within that project.

  • database_id: the source database id to recreate in the emulator (and, for the schema / all copy modes, copy schema and data from).

Spanner uses database_id rather than the fixed database slot above because the two mean different things. The fixed slot is an override target: the operator rewrites the app's database var to point at the branch's database. Spanner never rewrites it - the app keeps its own database id and is redirected wholesale by SPANNER_EMULATOR_HOST - so its database is a read-only locator the init sidecar uses to pick which source database to recreate, exactly like project and instance. The distinct name also keeps it from colliding with the flattened fixed database slot.

Unknown keys are rejected by the operator for the resolved engine.

The type of environment variable source for connection params.

feature.env

Allows the user to set or override the local process' environment variables with the ones from the remote pod.

Can be set to one of the options:

  1. false - Disables the feature, won't have remote environment variables.

  2. true - Enables the feature, will obtain remote environment variables.

  3. object - see below (means true + additional configuration).

Which environment variables to load from the remote pod are controlled by setting either include or exclude.

See the environment variables reference for more details.

feature.env.env_file

Allows for passing environment variables from an env file.

These variables will override environment fetched from the remote target.

feature.env.exclude

Include the remote environment variables in the local process that are NOT specified by this option. Variable names can be matched using * and ? where ? matches exactly one occurrence of any character and * matches arbitrary many (including zero) occurrences of any character.

Some of the variables that are excluded by default: PATH, HOME, HOMEPATH, CLASSPATH, JAVA_EXE, JAVA_HOME, PYTHONPATH, TMPDIR, TMP, TEMP.

Can be passed as a list or as a semicolon-delimited string (e.g. "VAR;OTHER_VAR").

feature.env.include

Include only these remote environment variables in the local process. Variable names can be matched using * and ? where ? matches exactly one occurrence of any character and * matches arbitrary many (including zero) occurrences of any character.

Can be passed as a list or as a semicolon-delimited string (e.g. "VAR;OTHER_VAR").

Some environment variables are excluded by default (PATH for example), including these requires specifying them with include

feature.env.load_from_process

Allows for changing the way mirrord loads remote environment variables. If set, the variables are fetched after the user application is started.

This setting is meant to resolve issues when using mirrord via the IntelliJ plugin on WSL and the remote environment contains a lot of variables.

feature.env.mapping

Specify map of patterns that if matched will replace the value according to specification.

Capture groups are allowed.

Example:

Will do the next replacements for environment variables that match:

  • CONNECTION_TIMEOUT: 500 => CONNECTION_TIMEOUT: 10000

  • LOG_FILE_VERBOSITY: info => LOG_FILE_VERBOSITY: debug

  • DATA_1234: common-value => DATA_1234: magic-value

feature.env.override

Allows setting or overriding environment variables (locally) with a custom value.

For example, if the remote pod has an environment variable REGION=1, but this is an undesirable value, it's possible to use override to set REGION=2 (locally) instead.

Environment specified here will also override variables passed via the env file.

feature.env.unset

Allows unsetting environment variables in the executed process.

This is useful for when some system/user-defined environment like AWS_PROFILE make the application behave as if it's running locally, instead of using the remote settings. The unsetting happens from extension (if possible)/CLI and when process initializes. In some cases, such as Go the env might not be able to be modified from the process itself. This is case insensitive, meaning if you'd put AWS_PROFILE it'd unset both AWS_PROFILE and Aws_Profile and other variations.

feature.fs

Allows the user to specify the default behavior for file operations:

  1. "read" or true - Read from the remote file system (default)

  2. "write" - Read/Write from the remote file system.

  3. "local" or false - Read from the local file system.

  4. "localwithoverrides" - perform fs operation locally, unless the path matches a pre-defined or user-specified exception.

Note: by default, some paths are read locally or remotely, regardless of the selected FS mode. This is described in further detail below.

Besides the default behavior, the user can specify behavior for specific regex patterns. Case insensitive.

  1. "read_write" - List of patterns that should be read/write remotely.

  2. "read_only" - List of patterns that should be read only remotely.

  3. "local" - List of patterns that should be read locally.

  4. "not_found" - List of patterns that should never be read nor written. These files should be treated as non-existent.

  5. "mapping" - Map of patterns and their corresponding replacers. The replacement happens before any specific behavior as defined above or mode (uses Regex::replace)

The logic for choosing the behavior is as follows:

  1. Check against "mapping" if path needs to be replaced, if matched then continue to next step with new path after replacements otherwise continue as usual.

  2. Check if one of the patterns match the file path, do the corresponding action. There's no specified order if two lists match the same path, we will use the first one (and we do not guarantee what is first).

    Warning: Specifying the same path in two lists is unsupported and can lead to undefined behaviour.

  3. There are pre-defined exceptions to the set FS mode.

  4. Paths that match the pre-defined patterns for Linux/MacOS or for Windows are read locally by default.

  5. Paths that match the pre-defined patterns for Linux/MacOS or for Windows are read remotely by default when the mode is localwithoverrides.

  6. Paths that match the pre-defined patterns for Linux/MacOS or for Windows under the running user's home directory will not be found by the application when the mode is not local.

In order to override that default setting for a path, or a pattern, include it the appropriate pattern set from above. E.g. in order to read files under /etc/ remotely even though it is covered by the set of pre-defined patterns that are read locally by default, add "^/etc/." to the read_only set.

  1. If none of the above match, use the default behavior (mode).

For more information, check the file operations technical reference.

feature.fs.local

Specify file path patterns that if matched will be opened locally.

Windows

Patterns are matched against a unix-style form of the requested path, not the raw Windows path. Before matching, the drive letter is stripped and backslashes are converted to forward slashes, so D:\Workspaces\myapp\app.json is matched as /Workspaces/myapp/app.json.

Patterns must therefore be written with forward slashes. Backslashes in the regex (e.g. "\\\\Workspaces\\\\") will never match anything, because the input string the regex sees contains no backslashes at all — they were stripped during translation.

feature.fs.mapping

Specify map of patterns that if matched will replace the path according to specification.

Capture groups are allowed. Matching is case-insensitive and uses Regex::replace, so the replacement value supports $1 / ${name} substitutions.

Unix (Linux, macOS)

Patterns are matched against the path exactly as the application requested it.

Example:

Will produce the following replacements for any io operation:

/home/johndoe/dev/tomcat/context.xml => /etc/tomcat/context.xml /home/johndoe/dev/config/api/app.conf => /mnt/configs/johndoe-api/app.conf

Windows

Patterns are matched against a unix-style form of the requested path, not the raw Windows path. Before matching, the drive letter is stripped and backslashes are converted to forward slashes, so:

D:\Workspaces\myapp\config\app.json is matched as /Workspaces/myapp/config/app.json

Patterns must therefore be written with forward slashes. Backslashes in the regex (e.g. "\\\\Workspaces\\\\") will never match anything, because the input string the regex sees contains no backslashes at all — they were stripped during translation.

The replacement value is sent to the agent as-is and is what the remote (Linux) pod will see on disk, so it should also use forward slashes.

Example:

Will produce the following replacement:

D:\Workspaces\myapp\config\app.json => /etc/myapp/app.json

Caveats

  • Relative paths: this feature (currently) does not apply mappings to relative paths, e.g. ../dev.

feature.fs.mode

feature.fs.mode

Configuration for enabling read-only or read-write file operations.

These options are overridden by user specified overrides and mirrord default overrides.

If you set "localwithoverrides" then some files can be read/write remotely based on our default/user specified. Default option for general file configuration.

The accepted values are: "local", "localwithoverrides", "read", or "write".

feature.fs.mode.local

mirrord won't do anything fs-related, all operations will be local.

feature.fs.mode.localwithoverrides

mirrord will run overrides on some file operations, but most will be local.

feature.fs.mode.read

mirrord will read files from the remote, but won't write to them.

feature.fs.mode.write

mirrord will read/write from the remote.

feature.fs.not_found

Specify file path patterns that if matched will be treated as non-existent.

Windows

Patterns are matched against a unix-style form of the requested path, not the raw Windows path. Before matching, the drive letter is stripped and backslashes are converted to forward slashes, so D:\Workspaces\myapp\app.json is matched as /Workspaces/myapp/app.json.

Patterns must therefore be written with forward slashes. Backslashes in the regex (e.g. "\\\\Workspaces\\\\") will never match anything, because the input string the regex sees contains no backslashes at all — they were stripped during translation.

feature.fs.prefetch

Remote paths to download from the target before the local process starts.

Each path is copied from the remote filesystem into a temporary local directory, along with its permissions. Operations on these paths are then served from that local copy, without involving the agent at all. Directories are copied recursively.

Writes go to the copy as well, and are never sent to the target. The application reads back whatever it wrote for the rest of the run, and the copy is abandoned when the run ends, leaving the target untouched. A write reaches the copy only when the mode would otherwise have sent it to the target, that is under write; under the other modes writes stay on the local filesystem under their original path, as they do for every other file.

The copy keeps the permissions it had in the target, so a file that is read-only there is read-only here, and writing to it fails locally much as it would remotely.

Do not prefetch secrets. The copy is written to a temporary directory on the machine running mirrord, guarded by nothing more than that machine's own permissions, rather than by the cluster. It is deleted when the session ends, but a session that is killed outright leaves it behind, since nothing gets to run.

Creating, deleting and renaming still act on the target: a file created under a prefetched directory is not part of the copy, and deleting or renaming a prefetched path takes effect remotely rather than in the copy.

This trades startup time for read throughput, and is meant for applications that repeatedly read a small and stable set of remote files, e.g. an HTTP server that reads /etc/ssl on every request.

Because the copy is taken once, before the application starts, changes made to these paths in the pod afterwards are invisible to the application.

Paths must start with /, as they are resolved in the remote pod, where the local process's working directory is meaningless.

Not supported on Windows, where the option is ignored.

feature.fs.prefetch_timeout

How long to wait, in seconds, for each request to the agent made while copying prefetch paths. By default, the value is 30 seconds.

The limit is per request rather than for the whole copy, which makes many requests: one per directory listing, and one per chunk of every file. Raise it when copying from a slow or distant cluster, where a single request can outlast the default.

A path that runs out of time is skipped with a warning, and is read from the remote as usual.

feature.fs.read_only

Specify file path patterns that if matched will be read from the remote. if file matching the pattern is opened for writing or read/write it will be opened locally.

Windows

Patterns are matched against a unix-style form of the requested path, not the raw Windows path. Before matching, the drive letter is stripped and backslashes are converted to forward slashes, so D:\Workspaces\myapp\app.json is matched as /Workspaces/myapp/app.json.

Patterns must therefore be written with forward slashes. Backslashes in the regex (e.g. "\\\\Workspaces\\\\") will never match anything, because the input string the regex sees contains no backslashes at all — they were stripped during translation.

feature.fs.read_write

Specify file path patterns that if matched will be read and written to the remote.

Windows

Patterns are matched against a unix-style form of the requested path, not the raw Windows path. Before matching, the drive letter is stripped and backslashes are converted to forward slashes, so D:\Workspaces\myapp\app.json is matched as /Workspaces/myapp/app.json.

Patterns must therefore be written with forward slashes. Backslashes in the regex (e.g. "\\\\Workspaces\\\\") will never match anything, because the input string the regex sees contains no backslashes at all — they were stripped during translation.

feature.fs.readonly_file_buffer

Sets buffer size for read-only remote files in bytes. By default, the value is 128000 bytes, or 128 kB.

Setting the value to 0 disables file buffering. Otherwise, read-only remote files will be read in chunks and buffered locally. This improves performance when the user application reads data in small portions.

feature.hostname

Should mirrord return the hostname of the target pod when calling gethostname

feature.magic

Sensible defaults that improve the experience for most users. Each flag can be disabled individually if it conflicts with your setup.

Sensible default behaviors that help most users. Disable individual flags only if they conflict with your setup.

feature.magic.auto_mount

Kubernetes mounts ConfigMaps, Secrets, and volumes (e.g. PVCs) into the target container at fixed paths. When mirrord runs your process locally, those paths either don't exist or hold unrelated local data, so the process can't read the configuration or secrets it expects from the pod.

When enabled, mirrord reads the target container's volume mounts from the remote pod spec and adds their mount paths to feature.fs.read_only, so the local process transparently reads those files from the remote pod while still writing locally.

This matters when the file system mode is localwithoverrides: the mounted paths would otherwise be served locally and not exist, so auto_mount forces them to be read from the remote pod. In the default read mode files are already read remotely, and in fully local mode all overrides are ignored, so auto_mount has no observable effect in either of those modes.

Paths you've explicitly marked local via feature.fs.local are left untouched.

Disable this only if you intentionally want the mounted paths served from the local file system.

Defaults to true.

feature.magic.aws

The AWS CLI prefers local credentials (e.g. ~/.aws, AWS_PROFILE) over the remote pod's identity (IAM role, instance profile, IRSA). When those local credentials are present, the pod's own identity is never used, which is rarely what you want in a mirrord session.

When enabled, mirrord makes local AWS configuration unavailable to the process by:

  • Unsetting AWS_PROFILE and related AWS environment variables.

  • Mapping ~/.aws to a temporary directory, so the AWS CLI cannot read local credentials and also has a writable location for its credential cache (avoiding errors on cache writes).

This allows the remote pod's IAM role / instance profile to be used as intended.

Disable this only if you intentionally need local AWS credentials inside the local mirrord' process.

Defaults to true.

feature.magic.turbo

Next.js + Turbopack runs transforms (e.g. PostCSS for CSS) in pooled Node worker subprocesses, which talk to the parent over a loopback TCP channel (the parent listens on 127.0.0.1:0 and the worker connects back). With the mirrord layer loaded into the worker, that loopback connection is routed through the agent (remote) by default, so the worker never reaches the local parent and the build fails (e.g. next dev crashes compiling CSS).

When enabled, mirrord detects Next.js processes and keeps their loopback IPC local by turning on feature.network.outgoing.ignore_localhost for the Next.js process and the Turbopack workers it spawns.

Disable this only if you intentionally need outgoing localhost connections from a Next.js process to be routed to the remote pod.

Defaults to true.

feature.network

Controls mirrord network operations.

See the network traffic reference for more details.

feature.network.dns

Resolve DNS via the remote pod.

Defaults to true.

Mind that:

  • DNS resolving can be done in multiple ways. Some frameworks use getaddrinfo/gethostbyname functions, while others communicate directly with the DNS server at port 53 and perform a sort of manual resolution. Just enabling the dns feature in mirrord might not be enough. If you see an address resolution error, try enabling the fs feature, and setting read_only: ["/etc/resolv.conf"].

  • DNS filter currently works only with frameworks that use getaddrinfo/gethostbyname functions.

feature.network.dns.filter

List of addresses/ports/subnets that should be resolved through either the remote pod or local app, depending how you set this up with either remote or local.

You may use this option to specify when DNS resolution is done from the remote pod (which is the default behavior when you enable remote DNS), or from the local app (default when you have remote DNS disabled).

Takes a list of values, such as:

  • Only queries for hostname my-service-in-cluster will go through the remote pod.

  • Only queries for addresses in subnet 1.1.1.0/24 with service port 1337 will go through the remote pod.

  • Only queries for hostname google.com with service port 1337 or 7331 will go through the remote pod.

  • Only queries for localhost with service port 1337 will go through the local app.

  • Only queries with service port 1337 or 7331 will go through the local app.

Valid values follow this pattern: [name|address|subnet/mask][:port].

Host names listed in feature.network.outgoing.filter are automatically appended here on the matching side, so DNS resolution stays on the same side as the connection (e.g. outgoing.filter.local = ["some.domain.com"] implies dns.filter.local = ["some.domain.com"]).

When filters are specified under local, matching DNS queries will go through the local app , everything else will go through the remote pod.

When filters are specified under remote, matching DNS queries will go through the remote pod, everything else will go through local.

feature.network.incoming

Controls the incoming TCP traffic feature.

See the incoming reference for more details.

Incoming traffic supports 3 modes of operation:

  1. Mirror (default): Sniffs the TCP data from a port, and forwards a copy to the interested listeners;

  2. Steal: Captures the TCP data from a port, and forwards it to the local process.

  3. Off: Disables the incoming network feature.

This field can either take an object with more configuration fields (that are documented below), or alternatively -

  • A boolean:

    • true: use the default configuration, same as not specifying this field at all.

    • false: disable incoming configuration.

  • One of the incoming modes (lowercase).

Examples:

Steal all the incoming traffic:

Disable the incoming traffic feature:

Steal only traffic that matches the http_filter (steals only HTTP traffic).

feature.network.incoming.http_filter

Filter configuration for the HTTP traffic stealer feature.

Allows the user to set a filter (regex) for the HTTP headers, so that the stealer traffic feature only captures HTTP requests that match the specified filter, forwarding unmatched requests to their original destinations.

Only does something when feature.network.incoming.mode is set as "steal", ignored otherwise.

The recommended way to filter a single developer session is to propagate a W3C baggage or tracestate entry such as mirrord-session={{ key }} from the caller, and match that value here. This works well across proxies, service meshes, and tracing-aware clients.

For example, to filter on a baggage header:

Setting that filter will make mirrord only steal requests whose baggage header contains mirrord-session={{ key }}.

If your traffic already propagates tracestate, you can filter on it the same way:

For example, to filter based on path:

Setting this filter will make mirrord only steal requests to URIs starting with "/api/".

This can be useful for filtering out Kubernetes liveness, readiness and startup probes. For example, for avoiding stealing any probe sent by kubernetes, you can set this filter:

Setting this filter will make mirrord only steal requests that do have a user agent that does not begin with "kube-probe".

Similarly, you can exclude certain paths using a negative look-ahead:

Setting this filter will make mirrord only steal requests to URIs that do not start with "/health/".

With all_of and any_of, you can use multiple HTTP filters at the same time.

If you want to steal HTTP requests that match every pattern specified, use all_of. For example, this filter steals only POST requests to endpoint /api/my-endpoint whose baggage header contains mirrord-session={{ key }}.

If you want to steal HTTP requests that match any of the patterns specified, use any_of. For example, this filter steals HTTP requests to /api/my-endpoint, or requests whose baggage header contains mirrord-session={{ key }}.

feature.network.incoming.http_filter.all_of

An array of HTTP filters.

Each inner filter specifies a header, path, method, body, or jq filter. Requests must match all of the filters to be stolen.

Cannot be an empty list.

Example:

feature.network.incoming.http_filter.any_of

An array of HTTP filters.

Each inner filter specifies a header, path, method, body, or jq filter. Requests must match at least one of the filters to be stolen.

Cannot be an empty list.

Example:

feature.network.incoming.http_filter.body_filter

Matches the request based on the contents of its body.

Currently only JSON body filtering is supported.

feature.network.incoming.inner_filter.body_filter.json

Tries to parse the body as a JSON object and find (a) matching subobjects(s).

query should be a valid JSONPath (RFC 9535) query string. matches should be a regex. Supports regexes validated by the fancy-regex crate

Example:

will match

The filter will match if there is at least one query result.

Non-string matches are stringified before being compared to the regex. To filter query results by type, the typeof function extension is provided. It takes in a single NodesType parameter and returns "null" | "bool" | "number" | "string" | "array" | "object", depending on the type of the argument. If not all nodes in the argument have the same type, it returns nothing.

Example:

will match

but not

To use with all_of or any_of, use the following syntax:

feature.network.incoming.http_filter.header_filter

Supports regexes validated by the fancy-regex crate.

The HTTP traffic feature converts the HTTP headers to HeaderKey: HeaderValue, case-insensitive.

The recommended pattern is to match a W3C baggage or tracestate entry such as mirrord-session={{ key }}.

feature.network.incoming.http_filter.header_filter_jq

Supports jq expressions, matches when the expression returns true. The expression is evaluated on each present header in the request, in HeaderKey: HeaderValue format.

feature.network.incoming.http_filter.method_filter

Supports standard HTTP methods, and non-standard HTTP methods.

Case-insensitive. If the request method matches the filter, the request is stolen.

feature.network.incoming.http_filter.path_filter

Supports regexes validated by the fancy-regex crate.

Case-insensitive. Tries to find match in the path (without query) and path+query. If any of the two matches, the request is stolen.

feature.network.incoming.http_filter.ports

Activate the HTTP traffic filter only for these ports. When absent, filtering will be done for all ports.

feature.network.incoming.https_delivery

DEPRECATED: use tls_delivery instead.

Stolen TLS traffic can be delivered to the local application either as TLS or as plain TCP. Note that stealing TLS traffic requires mirrord Operator support.

To have the stolen TLS traffic delivered with plain TCP, use:

To have the traffic delivered with TLS, use:

By default, the local mirrord TLS client will trust any certificate presented by the local application's TLS server. To override this behavior, you can either:

  1. Specify a list of paths to trust roots. These paths can lead either to PEM files or PEM file directories. Each found certificate will be used as a trust anchor.

  2. Specify a path to the cartificate chain used by the server.

Example with trust roots:

Example with certificate chain:

To make a TLS connection to the local application's server, mirrord's TLS client needs a server name. You can supply it manually like this:

If you don't supply the server name:

  1. If server_cert is given, and the found end-entity certificate contains a valid server name, this server name will be used;

  2. Otherwise, if the original client supplied an SNI extension, the server name from that extension will be used;

  3. Otherwise, if the stolen request's URL contains a valid server name, that server name will be used;

  4. Otherwise, localhost will be used.

If the local application's TLS server requires a client certificate (mutual TLS), give mirrord's TLS client one to present:

If the local application authorizes requests based on the identity of the client, give mirrord more client certificates to choose from. When the original client presented a certificate, mirrord presents the first of these with the same identity, and falls back to client_cert and client_key when none has it:

In preview sessions (mirrord preview start) the mirrord operator makes the TLS connection to the preview pod, so client_cert and client_key are read locally, stored in the session's Secret and presented by the operator. server_name is used the same way. The other settings, including client_identities, do not apply to previews: the operator always delivers over TLS and does not verify the preview pod's certificate.

When the target's own process already holds a client certificate the preview pod accepts, a preview can use it in place without copying it out of the cluster. Point client_cert and client_key at the paths inside the target's container and set client_cert_source to target; the operator reads the files from a running pod of the target:

feature.network.incoming.tls_delivery.client_cert

Path to a PEM file containing the certificate chain mirrord presents to the local application's TLS server, for applications that require a client certificate.

This file must contain at least one certificate. Must be set together with client_key.

feature.network.incoming.tls_delivery.client_cert_source

Where client_cert and client_key are read from. Defaults to local.

  • local: files on the machine running mirrord.

  • target: files inside the target's container, at the paths the target's own process uses. Only preview sessions (mirrord preview start) support this: the mirrord operator reads the files from a running pod of the target. mirrord exec has no access to the target's files and connects without a client certificate.

Where the client_cert and client_key files of [LocalTlsDelivery] live.

On the machine running mirrord.

Inside the target's container. Preview sessions only: the mirrord operator reads the files from a running pod of the target.

feature.network.incoming.tls_delivery.client_identities

Additional client certificates, for local applications that authorize requests based on the identity of the client.

When the original client presented a certificate, mirrord presents the first of these with the same identity. The identity is the set of subject alternative names, or the subject if the certificate has no SANs. DNS names are compared case-insensitively, all other names byte by byte. If none matches, or the original client presented no certificate, client_cert and client_key are used.

The original client's certificate is known only when the mirrord operator's TLS steal configuration verifies clients against trust roots.

Certificates can be presented only during the TLS handshake. Local applications that request a client certificate later (TLS 1.2 renegotiation, TLS 1.3 post-handshake authentication) are not supported.

These files are always read from the machine running mirrord, regardless of client_cert_source.

A client certificate with its private key, see [LocalTlsDelivery::client_identities].

Path to a PEM file containing the certificate chain.

This file must contain at least one certificate.

Path to a PEM file containing the private key of cert.

This file must contain exactly one private key.

feature.network.incoming.tls_delivery.client_key

Path to a PEM file containing the private key of client_cert.

This file must contain exactly one private key. Must be set together with client_cert.

feature.network.incoming.tls_delivery.protocol

Protocol to use when delivering the TLS traffic locally. Defaults to tls.

Path to a PEM file containing the certificate chain used by the local application's TLS server.

This file must contain at least one certificate. It can contain entries of other types, e.g private keys, which are ignored.

feature.network.incoming.tls_delivery.server_name

Server name to use when making a connection.

Must be a valid DNS name or an IP address.

feature.network.incoming.tls_delivery.trust_roots

Paths to PEM files and directories with PEM files containing allowed root certificates.

Directories are not traversed recursively.

Each certificate found in the files is treated as an allowed root. The files can contain entries of other types, e.g private keys, which are ignored.

feature.network.incoming.ignore_localhost

feature.network.incoming.ignore_ports

Ports to ignore when mirroring/stealing traffic, these ports will remain local.

Can be especially useful when feature.network.incoming.mode is set to "steal", and you want to avoid redirecting traffic from some ports (for example, traffic from a health probe, or other heartbeat-like traffic).

Mutually exclusive with feature.network.incoming.ports.

feature.network.incoming.listen_ports

Mapping for local ports to actually used local ports. When application listens on a port while steal/mirror is active we fallback to random ports to avoid port conflicts. Using this configuration will always use the specified port. If this configuration doesn't exist, mirrord will try to listen on the original port and if it fails it will assign a random port

This is useful when you want to access ports exposed by your service locally For example, if you have a service that listens on port 80 and you want to access it, you probably can't listen on 80 without sudo, so you can use [[80, 4480]] then access it on 4480 while getting traffic from remote 80. The value of port_mapping doesn't affect this.

feature.network.incoming.mode

Allows selecting between mirroring or stealing traffic.

Can be set to either "mirror" (default), "steal" or "off".

  • "mirror": Sniffs on TCP port, and send a copy of the data to listeners.

  • "off": Disables the incoming network feature.

  • "steal": Supports 2 modes of operation:

  1. Port traffic stealing: Steals all TCP data from a port, which is selected whenever the user listens in a TCP socket (enabling the feature is enough to make this work, no additional configuration is needed);

  2. HTTP traffic stealing: Steals only HTTP traffic, mirrord tries to detect if the incoming data on a port is HTTP (in a best-effort kind of way, not guaranteed to be HTTP), and steals the traffic on the port if it is HTTP;

feature.network.incoming.on_concurrent_steal

(Operator Only): Allows overriding port locks

Can be set to either "continue" or "override".

  • "continue": Continue with normal execution

  • "override": If port lock detected then override it with new lock and force close the original locking connection.

feature.network.incoming.port_mapping

Mapping for local ports to remote ports.

This is useful when you want to mirror/steal a port to a different port on the remote machine. For example, your local process listens on port 9333 and the container listens on port 80. You'd use [[9333, 80]]

feature.network.incoming.ports

When set, traffic will only be mirrored/stolen on these ports, and other ports will remain local. Otherwise, all ports are mirrored/stolen.

Mutually exclusive with feature.network.incoming.ignore_ports.

feature.network.incoming.tls_delivery

(Operator Only): configures how mirrord delivers stolen TLS traffic to the local application.

Stolen TLS traffic can be delivered to the local application either as TLS or as plain TCP. Note that stealing TLS traffic requires mirrord Operator support.

To have the stolen TLS traffic delivered with plain TCP, use:

To have the traffic delivered with TLS, use:

By default, the local mirrord TLS client will trust any certificate presented by the local application's TLS server. To override this behavior, you can either:

  1. Specify a list of paths to trust roots. These paths can lead either to PEM files or PEM file directories. Each found certificate will be used as a trust anchor.

  2. Specify a path to the cartificate chain used by the server.

Example with trust roots:

Example with certificate chain:

To make a TLS connection to the local application's server, mirrord's TLS client needs a server name. You can supply it manually like this:

If you don't supply the server name:

  1. If server_cert is given, and the found end-entity certificate contains a valid server name, this server name will be used;

  2. Otherwise, if the original client supplied an SNI extension, the server name from that extension will be used;

  3. Otherwise, if the stolen request's URL contains a valid server name, that server name will be used;

  4. Otherwise, localhost will be used.

If the local application's TLS server requires a client certificate (mutual TLS), give mirrord's TLS client one to present:

If the local application authorizes requests based on the identity of the client, give mirrord more client certificates to choose from. When the original client presented a certificate, mirrord presents the first of these with the same identity, and falls back to client_cert and client_key when none has it:

In preview sessions (mirrord preview start) the mirrord operator makes the TLS connection to the preview pod, so client_cert and client_key are read locally, stored in the session's Secret and presented by the operator. server_name is used the same way. The other settings, including client_identities, do not apply to previews: the operator always delivers over TLS and does not verify the preview pod's certificate.

When the target's own process already holds a client certificate the preview pod accepts, a preview can use it in place without copying it out of the cluster. Point client_cert and client_key at the paths inside the target's container and set client_cert_source to target; the operator reads the files from a running pod of the target:

feature.network.incoming.tls_delivery.client_cert

Path to a PEM file containing the certificate chain mirrord presents to the local application's TLS server, for applications that require a client certificate.

This file must contain at least one certificate. Must be set together with client_key.

feature.network.incoming.tls_delivery.client_cert_source

Where client_cert and client_key are read from. Defaults to local.

  • local: files on the machine running mirrord.

  • target: files inside the target's container, at the paths the target's own process uses. Only preview sessions (mirrord preview start) support this: the mirrord operator reads the files from a running pod of the target. mirrord exec has no access to the target's files and connects without a client certificate.

Where the client_cert and client_key files of [LocalTlsDelivery] live.

On the machine running mirrord.

Inside the target's container. Preview sessions only: the mirrord operator reads the files from a running pod of the target.

feature.network.incoming.tls_delivery.client_identities

Additional client certificates, for local applications that authorize requests based on the identity of the client.

When the original client presented a certificate, mirrord presents the first of these with the same identity. The identity is the set of subject alternative names, or the subject if the certificate has no SANs. DNS names are compared case-insensitively, all other names byte by byte. If none matches, or the original client presented no certificate, client_cert and client_key are used.

The original client's certificate is known only when the mirrord operator's TLS steal configuration verifies clients against trust roots.

Certificates can be presented only during the TLS handshake. Local applications that request a client certificate later (TLS 1.2 renegotiation, TLS 1.3 post-handshake authentication) are not supported.

These files are always read from the machine running mirrord, regardless of client_cert_source.

A client certificate with its private key, see [LocalTlsDelivery::client_identities].

Path to a PEM file containing the certificate chain.

This file must contain at least one certificate.

Path to a PEM file containing the private key of cert.

This file must contain exactly one private key.

feature.network.incoming.tls_delivery.client_key

Path to a PEM file containing the private key of client_cert.

This file must contain exactly one private key. Must be set together with client_cert.

feature.network.incoming.tls_delivery.protocol

Protocol to use when delivering the TLS traffic locally. Defaults to tls.

Path to a PEM file containing the certificate chain used by the local application's TLS server.

This file must contain at least one certificate. It can contain entries of other types, e.g private keys, which are ignored.

feature.network.incoming.tls_delivery.server_name

Server name to use when making a connection.

Must be a valid DNS name or an IP address.

feature.network.incoming.tls_delivery.trust_roots

Paths to PEM files and directories with PEM files containing allowed root certificates.

Directories are not traversed recursively.

Each certificate found in the files is treated as an allowed root. The files can contain entries of other types, e.g private keys, which are ignored.

feature.network.ipv6

Enable IPv6 support, letting the application open IPv6 sockets and listen to or send traffic over IPv6. Enabled by default. Set to false to make IPv6 socket creation fail with EAFNOSUPPORT, like on a host without an IPv6 stack.

feature.network.outgoing

Tunnel outgoing network operations through mirrord.

See the outgoing reference for more details.

You can use either the true or false values to turn outgoing traffic tunneling on or off.

Alternatively, you can use more fine-grained configuration.

feature.network.outgoing.filter

Filters that are used to send specific traffic from either the remote pod or the local app

List of addresses/ports/subnets that should be sent through either the remote pod or local app, depending how you set this up with either remote or local.

You may use this option to specify when outgoing traffic is sent from the remote pod (which is the default behavior when you enable outgoing traffic), or from the local app (default when you have outgoing traffic disabled).

Takes a list of values, such as:

  • Only UDP traffic on subnet 1.1.1.0/24 on port 1337 will go through the remote pod.

  • Only UDP and TCP traffic on resolved address of google.com on port 1337 and 7331 will go through the remote pod.

  • Only TCP traffic on localhost on port 1337 will go through the local app, the rest will be emitted remotely in the cluster.

  • Only outgoing traffic on port 1337 and 7331 will go through the local app.

Valid values follow this pattern: [protocol]://[name|address|subnet/mask]:[port].

Host names listed here are automatically mirrored into feature.network.dns.filter on the matching side, so the name is resolved on the side that handles the connection. For example, { "local": ["some.domain.com"] } implies dns.filter.local = ["some.domain.com"] even if dns.filter is otherwise unset.

When filters are specified under local, matching traffic will go through the local app, everything else will go through the remote pod.

When filters are specified under remote, matching traffic will go through the remote pod, everything else will go through local.

feature.network.outgoing.ignore_localhost

Defaults to false.

feature.network.outgoing.tcp

Defaults to true.

feature.network.outgoing.udp

Defaults to true.

feature.network.outgoing.unix_streams

Connect to these unix streams remotely (and to all other paths locally).

You can either specify a single value or an array of values. Each value is interpreted as a regular expression (Supported Syntax).

When your application connects to a unix socket, the target address will be converted to a string (non-utf8 bytes are replaced by a placeholder character) and matched against the set of regexes specified here. If there is a match, mirrord will connect your application with the target unix socket address on the target pod. Otherwise, it will leave the connection to happen locally on your machine.

feature.preview

Configuration for preview environments.

Controls the lifetime and creation behavior of preview sessions.

feature.preview.config_mounts

Files to mount into the preview pod at session start.

Each entry projects a single file at an absolute path inside the container's filesystem, without shadowing the surrounding directory's other contents. Useful for overriding individual config files (/etc/app/config.yaml, /etc/nginx/conf.d/custom.conf, ...) without rebuilding the image.

Files are read once at session creation and never refreshed — re-run mirrord preview start with the same key to change them.

config_mounts is not a confidentiality boundary: the payload is stored on the PreviewSession resource and is visible to anyone with get permission on it. Do not put credentials or secrets here.

Each entry sources its content one of two ways:

  • Inline: set type ("text" or "binary") and payload directly.

  • From file: set from_file to a path on the local filesystem. The file is read at session creation time; valid UTF-8 contents are sent as "text", anything else is base64-encoded and sent as "binary". The local path is not transmitted to the operator.

payload/type and from_file are mutually exclusive on a single entry.

Implementation

Each session creates one ConfigMap owned by the PreviewSession, holding all mount payloads. The ConfigMap is mounted into the preview pod with one per-file subPath bind per entry, so each mount overlays a single path without shadowing the surrounding directory. An entry inside a ConfigMap, Secret, downward API, or projected volume the container already mounts is projected into that volume instead. The ConfigMap is garbage-collected automatically when the session ends.

Because both the PreviewSession resource and the generated ConfigMap live in etcd, the combined size of all payload payloads in a single session is bound by Kubernetes' ~1 MiB per-object limit. For "text" payloads that's roughly 1 MiB of content; for "binary", base64 inflates the encoded form by ~33%, leaving roughly 750 KiB of raw bytes. Exceeding the limit causes the apiserver to reject the session at creation time.

A single file to project into the preview pod's container filesystem.

Either payload+type (inline) or from_file (load from disk) must be set; the two forms are mutually exclusive. After [ConfigMount::resolve] has been called, the result is guaranteed to have payload and r#type set and from_file cleared. This form gets sent to the operator.

Local filesystem path to read the file from. The contents are loaded at session creation time and sent as "text" (verbatim) if valid UTF-8, otherwise base64-encoded and sent as "binary". Mutually exclusive with payload.

Absolute path inside the preview pod's container where the file should appear. The surrounding directory's other contents (if any) are left untouched, only this one path is overlaid.

Inline file contents. Interpretation depends on type: for "text", written to the file byte-for-byte; for "binary", base64-decoded first. Mutually exclusive with from_file.

How the payload payload should be interpreted when writing it to the file. "text" for verbatim UTF-8 content, "binary" for base64-encoded bytes. Required when payload is set; determined automatically when from_file is used.

Encoding of a [ConfigMount::payload] payload.

payload is base64-encoded and is decoded before being written. Used for binary files that can't safely live in a JSON string.

payload is written to the file verbatim. Used for human-readable config files (YAML, TOML, JSON, env files, shell scripts, ...).

feature.preview.creation_timeout_secs

How long (in seconds) the CLI waits for the preview session to become ready. If the session hasn't reached Ready within this time, the CLI deletes it.

feature.preview.cronjob

Settings that only apply when the preview target is a cronjob/<name>.

A CronJob preview is an isolated copy of the source CronJob running your image, with the same env, DB branch, and mount overrides other previews get. It is triggered once right after the session starts (unless trigger_on_start is false), and then keeps running on its schedule until the session ends.

CronJob-target settings for preview sessions.

feature.preview.cronjob.schedule

Cron schedule for the preview CronJob, in Kubernetes CronJob syntax ("0 * * * *", "@hourly", ...). When omitted, the preview inherits the source CronJob's schedule.

Whatever the schedule, the preview CronJob is also triggered once right after the session starts unless trigger_on_start is false.

feature.preview.cronjob.trigger_on_start

Run the preview CronJob once right after the session starts, regardless of its schedule, so you see a run without waiting for the next scheduled time. Defaults to true.

Set to false for jobs whose timing matters (a report that must only run in its window, a job that assumes the previous scheduled run finished), so the preview runs on the schedule alone.

feature.preview.idle

Idle-mode settings: run the preview with zero pods while it receives no traffic, and boot them back up when traffic arrives.

Idle-mode settings for preview sessions.

An idle preview keeps its session, traffic listener, queue splits, and database branches alive, but runs zero pods. The first stolen request or routed queue message boots the pods back up. HTTP requests arriving while the pods boot are held by the operator until a pod is ready or the wake timeout expires.

feature.preview.idle.sleep_after_secs

Scale the preview pods to zero after this many seconds without traffic. Must be at least 30. When unset, the session never idles automatically.

feature.preview.idle.start_idle

Start the preview session with zero pods. The first matching request or queue message boots them.

feature.preview.idle.wake_timeout_secs

How long a waking session holds incoming requests while waiting for a preview pod to become ready, before letting them fail. Defaults to the operator's default (90 seconds).

A pod scheduled onto a node that has to pull its image first can take longer than the default, and the held requests then fail; raise this value (or pre-pull the image) for such setups.

feature.preview.image

Container image to run in the preview pod. The image must be pre-built and pushed to a registry accessible by the cluster.

feature.preview.labels

Filters labels copied from the target pod template to the preview pod.

feature.preview.replicas

Number of preview pods to deploy.

feature.preview.secret_mounts

Files to mount into the preview pod at session start, stored as a Kubernetes Secret instead of on the PreviewSession resource.

Same shape and behavior as config_mounts: each entry projects a single file at an absolute path inside the container's filesystem without shadowing the surrounding directory, and files are read once at session creation and never refreshed.

Use secret_mounts for sensitive files (credentials, connection strings, ...). Unlike config_mounts, the file contents are never stored on the PreviewSession resource. The CLI sends them to the operator, which creates a Secret holding them; the session stores only where each file mounts, not the contents. Access to the contents can then be controlled via RBAC on the Secret independently of who can read the session.

Each entry sources its content one of two ways:

  • Inline: set type ("text" or "binary") and payload directly.

  • From file: set from_file to a path on the local filesystem. The file is read at session creation time; valid UTF-8 contents are sent as "text", anything else is base64-encoded and sent as "binary". The local path is not transmitted to the operator.

payload/type and from_file are mutually exclusive on a single entry.

Implementation

The operator creates one Secret per session, holding all mount contents, with its own service account - so the developer running the CLI does not need permission to create Secrets. The Secret carries the session's owner reference and is garbage-collected when the session ends. It is mounted into the preview pod with one per-file subPath bind per entry, so each mount overlays a single path without shadowing the surrounding directory. An entry inside a ConfigMap, Secret, downward API, or projected volume the container already mounts is projected into that volume instead.

The same ~1 MiB per-object Kubernetes limit as config_mounts applies to the combined size of all contents in a single session.

A single file to project into the preview pod's container filesystem.

Either payload+type (inline) or from_file (load from disk) must be set; the two forms are mutually exclusive. After [ConfigMount::resolve] has been called, the result is guaranteed to have payload and r#type set and from_file cleared. This form gets sent to the operator.

Local filesystem path to read the file from. The contents are loaded at session creation time and sent as "text" (verbatim) if valid UTF-8, otherwise base64-encoded and sent as "binary". Mutually exclusive with payload.

Absolute path inside the preview pod's container where the file should appear. The surrounding directory's other contents (if any) are left untouched, only this one path is overlaid.

Inline file contents. Interpretation depends on type: for "text", written to the file byte-for-byte; for "binary", base64-decoded first. Mutually exclusive with from_file.

How the payload payload should be interpreted when writing it to the file. "text" for verbatim UTF-8 content, "binary" for base64-encoded bytes. Required when payload is set; determined automatically when from_file is used.

Encoding of a [ConfigMount::payload] payload.

payload is base64-encoded and is decoded before being written. Used for binary files that can't safely live in a JSON string.

payload is written to the file verbatim. Used for human-readable config files (YAML, TOML, JSON, env files, shell scripts, ...).

feature.preview.spec_resources

Kubernetes manifest files (or directories of them) to build the preview from, instead of the target's live spec. Same as mirrord preview start --resource <path>, which replaces this list when given.

Point it at the manifests you already keep for the service (the desired state, for example the files your pull request changes). From every *.yaml / *.yml document, mirrord keeps only the target itself and the ConfigMaps and Secrets its pod uses (through env, envFrom, or volumes). Everything else in the files, such as an Ingress or another Deployment, is skipped. Of what is left, objects identical to what is live are skipped too.

  • The target's pod template from the files becomes the preview pod's spec (with your image). When the files do not define the target, the live one is used.

  • Changed or new ConfigMaps and Secrets are created as copies that belong to the preview, and the preview pod uses those copies. The live ones, which the real app uses, are never changed. The copies are deleted when the preview ends.

Nothing is created when a file fails to parse or the cluster rejects a changed object. Run mirrord preview diff to see what would change without creating anything.

feature.preview.ttl_mins

How long (in minutes) the preview session is allowed to live after creation. The operator will terminate the session when this time elapses.

Set to "infinite" to disable TTL.

Mutually exclusive with ttl_secs; when neither is set, defaults to 60 minutes.

A TTL value usable for either [PreviewConfig::ttl_mins] or [PreviewConfig::ttl_secs].

The unit (minutes or seconds) depends on which field carries the value; the variants themselves are unit-agnostic.

feature.preview.ttl_secs

Same as ttl_mins but expressed in seconds.

Set to "infinite" to disable TTL.

Mutually exclusive with ttl_mins.

A TTL value usable for either [PreviewConfig::ttl_mins] or [PreviewConfig::ttl_secs].

The unit (minutes or seconds) depends on which field carries the value; the variants themselves are unit-agnostic.

feature.split_queues

Define filters to split queues by, and make your local application consume only messages that match those filters. If you don't specify any filter for a queue that is however declared in the MirrordWorkloadQueueRegistry of the target you're using, a match-nothing filter will be used, and your local application will not receive any messages from that queue.

The queue splitting configuration. Each entry pairs a queue id with a filter that decides which messages from the original queue are delivered to the local application, based on message attributes or headers, and possibly on jq filters (for SQS and other body-aware brokers).

The queue ids have to match those defined in the target's MirrordSplitConfig (or the legacy MirrordWorkloadQueueRegistry / MirrordKafkaTopicsConsumer).

Two shapes are accepted. The classic map form keys each entry by its queue id, which means a given id can appear only once:

The list form moves the id into each entry, so the same id can be used more than once - for example to split a queue with the same name on two different brokers:

One queue to split: which broker it is on, which of its messages reach the local application, and what happens to those messages. The same struct backs both config shapes: in the list form it carries its queue_id, in the map form the id is the map key.

Adding a broker is one [QueueKind] variant; adding a filter option is one field here, read by every broker through the operator's shared filter code.

The composable filter. See feature.split_queues.{}.filter.

feature.split_queues.{}.filter

A composable message filter, shaped like the HTTP http_filter: one metadata regex, or an all_of / any_of list of metadata regexes.

A metadata regex is matched against every message attribute (SQS message attributes, Kafka and RabbitMQ headers, Pub/Sub attributes, Service Bus application properties, Temporal task metadata, top-level JSON fields for Redis Pub/Sub and BullMQ) rendered as <name>: <value>, the same way the HTTP filter sees headers. The message matches when any attribute line matches, so one regex can target an attribute by name (^tenant: blue$) or a value wherever it appears (.*mirrord-session={{ key }}.*). Matching is case sensitive.

Use filter or the older message_filter, not both. message_filter is a map from an exact attribute name to a regex on its value, and is equivalent to an all_of of one metadata filter per entry.

The message must match every filter in the list. Cannot be empty.

One filter inside all_of / any_of. Only metadata regexes for now; the list form leaves room for other leaf kinds without changing the shape.

A regex matched against each message attribute rendered as <name>: <value>.

The message must match at least one filter in the list. Cannot be empty.

One filter inside all_of / any_of. Only metadata regexes for now; the list form leaves room for other leaf kinds without changing the shape.

A regex matched against each message attribute rendered as <name>: <value>.

A regex matched against each message attribute rendered as <name>: <value>. Supports the syntax of the fancy-regex crate.

feature.split_queues.{}.jq_filter

When this field is specified, for each message, the jq filter runs on a JSON representation of the message. If the jq program outputs true, that message is considered as matching the filter. Combined with filter or message_filter, a message must match both.

For SQS, an SQS Message object is used.

For GCP Pub/Sub, the JSON representation of PubsubMessage is used.

For Kafka, an object with topic, partition, offset, timestamp, key, payload, and headers fields is used. key, payload, and header values are UTF-8 strings, or base64-encoded when not valid UTF-8. With payload_protobuf set, the object additionally has a payload_decoded field holding the payload decoded from protobuf.

For RabbitMQ, an object with headers (the AMQP basic-properties headers table), properties, and payload fields is used. The payload and header values are UTF-8 strings, or base64-encoded when not valid UTF-8.

For Azure Service Bus, an object with body, application_properties, message_id, content_type, and subject fields is used.

For Redis Pub/Sub, the message payload parsed as JSON is used. Messages whose payload is not valid JSON never match.

For Temporal, an object the operator builds for each task is used. Every object has a task_type field, set to either "activity" or "workflow". Activity tasks also carry workflow_namespace, workflow_id, run_id, workflow_type, activity_type, activity_id, attempt, header, and input (an array of the decoded arguments). Workflow tasks also carry workflow_id, run_id, workflow_type, attempt, task_queue, cron_schedule, identity, first_execution_run_id, header, search_attributes, memo, and input.

For BullMQ, the job's data field parsed as JSON is used. Jobs whose data is not valid JSON never match.

For NATS and NATSPubSub, an object with subject, headers, and payload fields is used. payload is the message body parsed as JSON when the body is JSON, and a string otherwise (base64-encoded when not valid UTF-8). Unlike NATS (JetStream), core NATS pub/sub stores nothing, so delivery to the local application is best-effort: messages published while the split is being set up or torn down are not replayed.

This can be used to filter messages based on their body content, for example.

This filter, for example, will tell mirrord to only make available to this local application messages with a json in the message body, with a customer_email field that contains "metalbear.com": ".Body | fromjson | .customer_email | test(\"metalbear\\\\.com\")"

feature.split_queues.{}.message_filter

The older filter shape: a mapping between message attribute (or header) names and regexes their values should match. The local application only receives messages that have all of the named attributes, each matching its pattern. Still supported; new configs should prefer filter, which can also match attributes without naming them and compose with any_of / all_of.

For Temporal the names are workflow_id, workflow_type, activity_type, header.<name>, or a search attribute key. For Redis Pub/Sub and BullMQ they are top-level fields of the JSON payload.

Decodes the raw protobuf payload into a payload_decoded field for jq_filter, for Kafka topics that carry plain protobuf instead of JSON. See feature.split_queues.{}.payload_protobuf.

feature.split_queues.{}.payload_protobuf

Only supported with queue_type of Kafka.

Decodes the raw protobuf bytes in the message payload before the jq_filter runs, for topics that carry plain protobuf (for example CDC events) instead of JSON. The decoded message is exposed to the jq program as an extra payload_decoded field, so filters can target schema fields directly:

The schema is compiled locally by the mirrord CLI (resolving imports on your machine), so the operator never needs access to your .proto files. Field names appear in payload_decoded exactly as written in the schema, enum values as their names, and 64-bit integers as JSON numbers. Fields at their default value are included. Messages that fail to decode with the given schema never match the filter and stay with the deployed application.

The payload must be plain protobuf: schema-registry framing (magic byte + schema id prefix) is not supported.

Base64-encoded serialized FileDescriptorSet, optionally gzip-compressed (plain protoc --descriptor_set_out --include_imports output works as-is). An alternative to schema_file for pre-compiled schemas; filled in automatically from schema_file during config resolution.

Extra import roots for compiling schema_file. The file's own directory is always an import root.

Fully-qualified name of the payload's message type, e.g. com.example.cdc.Record.

Path to the .proto file defining the payload's message type. Relative paths are resolved against the current working directory. Not needed when descriptor_base64 is provided.

feature.split_queues.{}.queue_id

The id of the queue to split, as it appears in the target's split configuration. List form only: in the map form the id is the key. Does not have to be unique across entries. Use * to split every queue of the given queue_type with this filter.

Empty only while a map-form entry is being read, before the key is copied in.

Whether matched messages are stolen from the deployed application or mirrored to it.

feature.split_queues.{}.queue_mode

Controls what happens to a message that matches this session's filter.

  • steal (default): the matched message is delivered only to this session, so the deployed application never sees it.

  • mirror: the matched message is delivered to this session and still delivered to the deployed application, so both process a copy. Temporal supports steal only: a mirror request on a Temporal task queue runs as steal.

Deliver matched messages to this session while the deployed application still gets them.

Take matched messages away from the deployed application (current behavior).

The broker this queue lives on.

feature.split_queues.{}.queue_type

The broker the queue lives on. One of SQS, Kafka, RMQ, GCPPubSub, RedisPubSub, AzureServiceBus, Temporal, BullMQ, NATS, or NATSPubSub.

The Display form is the snake_case name used in analytics keys and logs.

A queue type this version of mirrord does not know. Produced when an older operator reads a config written by a newer client; it never comes from a user config, which verify rejects with a clear error.

internal_proxy

Configuration for the internal proxy mirrord spawns for each local mirrord session that local layers use to connect to the remote agent

This is seldom used, but if you get ConnectionRefused errors, you might want to increase the timeouts a bit.

internal_proxy.idle_timeout

How much time to wait while we don't have any active connections before exiting.

Common cases would be running a chain of processes that skip using the layer and don't connect to the proxy.

internal_proxy.json_log

Whether the proxy should output logs in JSON format. If false, logs are output in human-readable format.

Defaults to true.

internal_proxy.log_destination

Set the log destination for the internal proxy.

  1. If the provided path ends with a separator (/ on UNIX, \ on Windows), it will be treated as a path to directory where the log file should be created.

  2. Otherwise, if the path exists, mirrord will check if it's a directory or not.

  3. Otherwise, it will be treated as a path to the log file.

mirrord will auto create all parent directories.

Defaults to a randomized path inside the temporary directory.

internal_proxy.log_level

Set the log level for the internal proxy.

The value should follow the RUST_LOG convention (i.e mirrord=trace).

Defaults to mirrord=info,warn.

internal_proxy.ping_interval

How often the internal proxy should ping the agent connection, in seconds.

Smaller values detect dropped operator connections faster, at the cost of more frequent ping traffic.

internal_proxy.process_logging_interval

How often to log information about connected processes in seconds.

This feature logs details about processes that are currently connected to the internal proxy, including their PID, process name, command line, and connection status.

internal_proxy.start_idle_timeout

How much time to wait for the first connection to the proxy in seconds.

Common cases would be running with dlv or any other debugger, which sets a breakpoint on process execution, delaying the layer startup and connection to proxy.

key

An identifier for a mirrord session.

The key can be referenced in your configuration using the {{ key }} template variable.

The recommended use is to propagate it in W3C baggage or tracestate, then filter on mirrord-session={{ key }} in feature.network.incoming.http_filter.

The key itself is templated, so instead of a literal it can be derived from another variable. Using git_branch gives each branch its own session without passing a key per run:

Priority (highest to lowest):

  1. CLI argument: mirrord exec --key my-key

  2. Environment variable: MIRRORD_KEY

  3. Config file: { "key": "my-key" }

  4. Fallback: A unique key is randomly generated if no other option is provided

kube_context

Kube context to use from the kubeconfig file. Will use current context if not specified.

kubeconfig

Path to a kubeconfig file, if not specified, will use KUBECONFIG, or ~/.kube/config, or the in-cluster config.

multi_cluster

Controls multi-cluster session behavior when connecting to a multi-cluster Primary operator. When set to false, forces a single-cluster session on the Primary cluster instead of creating a multi-cluster session that spans all workload clusters. When true or unset, multi-cluster sessions are used when the operator supports them.

operator

Whether mirrord should use the operator. If not set, mirrord will first attempt to use the operator, but continue without it in case of failure.

profile

Name of the mirrord profile to use.

To select a cluster-wide profile

To select a namespaced profile

sip_binaries

Binaries to patch (macOS SIP).

Use this when mirrord isn't loaded to protected binaries that weren't automatically patched.

Runs endswith on the binary path (so bash would apply to any binary ending with bash while /usr/bin/bash would apply only for that binary).

skip_build_tools

Allows mirrord to skip build tools. Useful when running command lines that build and run the application in a single command.

Defaults to true.

Build-Tools: ["as", "cc", "ld", "go", "air", "asm", "cc1", "cgo", "dlv", "gcc", "git", "link", "math", "cargo", "hpack", "rustc", "compile", "collect2", "cargo-watch", "debugserver"]

skip_extra_build_tools

Allows mirrord to skip the specified build tools. Useful when running command lines that build and run the application in a single command.

Must also enable skip_build_tools for this to take an effect.

It's similar to skip_processes, except that here it also skips SIP patching.

Accepts a single value, or an array of values.

skip_processes

Allows mirrord to skip unwanted processes.

Useful when process A spawns process B, and the user wants mirrord to operate only on process B. Accepts a single value, or an array of values.

skip_sip

Allows mirrord to skip patching (macOS SIP) unwanted processes.

When patching is skipped, mirrord will no longer be able to load into the process and its child processes.

Defaults to { "skip_sip": "git" }

When specified, the given value will replace the default list rather than being added to.

startup_retry

Controls how many times, and how often mirrord retries its initial Kubernetes API requests (e.g. for resolving the target or connecting to the mirrord Operator).

If you're having cluster connectivity issues when starting mirrord, consider increasing max_retries and changing both min_ms and max_ms to have mirrord retry some of its initial Kubernetes API requests.

startup_retry.max_ms

Sets the max interval (in milliseconds) of retries for Kubernetes API requests made by mirrord during startup (e.g. for resolving the target or connecting to the mirrord Operator).

Defaults to 5000 milliseconds.

startup_retry.max_retries

Sets the max amount of retries for Kubernetes API requests made by mirrord during startup (e.g. for resolving the target or connecting to the mirrord Operator).

If you want to disable request retries, set this value to 0.

Defaults to 2.

startup_retry.min_ms

Sets the min interval (in milliseconds) of retries for Kubernetes API requests made by mirrord during startup (e.g. for resolving the target or connecting to the mirrord Operator).

Defaults to 500 milliseconds.

target

Specifies the target and namespace to target.

The JSON configuration supports:

Target type
JSON object equivalent

targetless

{ "target": "targetless" }

pod

{ "target": { "pod": "pod-name", "container": "container-name" } }

deployment

{ "target": { "deployment": "deployment-name", "container": "container-name" } }

rollout

{ "target": { "rollout": "rollout-name", "container": "container-name" } }

job

{ "target": { "job": "job-name", "container": "container-name" } }

cronjob

{ "target": { "cron_job": "cronjob-name", "container": "container-name" } }

statefulset

{ "target": { "stateful_set": "statefulset-name", "container": "container-name" } }

service

{ "target": { "service": "service-name", "container": "container-name" } }

label

{ "target": { "labels": { "key": "value" }, "container": "container-name" } }

serverless

{ "target": { "service": "service-name", "container": "replice-id" } }

Please note that:

  • job, cronjob, statefulset and service targets require the mirrord Operator

  • job and cronjob targets use the copy_target feature, which mirrord enables automatically for them

Recommended object setup:

Equivalent shortened setup with a target:

The setup above will result in a session targeting the bear-pod Kubernetes pod in the user's default namespace. A target container will be chosen by mirrord.

Recommended object setup with a target container:

Shortened setup with a target container:

The setup above will result in a session targeting the bear-pod-container container in the bear-pod Kubernetes pod in the user's default namespace.

Complete object setup with a target container:

The setup above will result in a session targeting the bear-pod-container container in the bear-pod Kubernetes pod in the bear-pod-namespace namespace.

Setup with a namespace for a targetless run:

The setup above will result in a session without any target. Remote outgoing traffic and DNS will be done from the bear-namespace namespace.

target.namespace

Namespace where the target lives.

For targetless runs, this the namespace in which remote networking is done.

For Serverless runs, can be used as the environment name in mirrord Cloud

Defaults to the Kubernetes user's default namespace (defined in Kubernetes context).

target.path

Specifies the resource to target, can be a Kubernetes resource or mirrord Serverless one.

If not given, defaults to targetless.

Note: targeting services and whole workloads is available only in mirrord for Teams. If you target a workload without the mirrord Operator, it will choose a random pod replica to work with.

Supports:

Target type
Requires
JSON equivalent

targetless

—

"targetless"

pod

—

{ "pod": "pod-name", "container": "container-name" }

deployment

—

{ "deployment": "deployment-name", "container": "container-name" }

rollout

—

{ "rollout": "rollout-name", "container": "container-name" }

job

mirrord Operator; auto-enables copy_target

{ "job": "job-name", "container": "container-name" }

cronjob

mirrord Operator; auto-enables copy_target

{ "cron_job": "cronjob-name", "container": "container-name" }

statefulset

mirrord Operator

{ "stateful_set": "statefulset-name", "container": "container-name" }

service

mirrord Operator

{ "service": "service-name", "container": "container-name" }

replicaset

mirrord Operator

{ "replica_set": "replicaset-name", "container": "container-name" }

label

mirrord Operator

{ "labels": { "app": "api", "tier": "web" }, "container": "api" }

serverless

mirrord Cloud

{ "service": "service-name", "container": "replace-id" }

telemetry

Controls whether or not mirrord sends telemetry data to MetalBear cloud. Telemetry sent doesn't contain personal identifiers or any data that should be considered sensitive. It is used to improve the product. For more information

traceparent

OpenTelemetry (OTel) / W3C trace context. This is used in HTTP requests sent to the operator to manually set the parent trace of the entry point, which can help when processing traces. See OTel docs

Only relevant for use with the operator. For more details, read the docs on monitoring.

use_proxy

When disabled, mirrord will remove HTTP[S]_PROXY env variables before doing any network requests. This is useful when the system sets a proxy but you don't want mirrord to use it. This also applies to the mirrord process (as it just removes the env). If the remote pod sets this env, the mirrord process will still use it.

Last updated

Was this helpful?