{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "additionalProperties": false, "properties": { "version": { "type": "string", "description": "The version of the configuration file. This is used to ensure that the configuration file is compatible.", "enum": ["1"] }, "instance_id": { "type": "string", "description": "The unique identifier of the instance. This is used to identify the instance in the control plane and in the metrics." }, "graph": { "type": "object", "additionalProperties": false, "properties": { "token": { "type": "string", "description": "The token used to authenticate with other component from Cosmo. Can be omitted if the router is started with a static execution config." }, "sign_key": { "type": "string", "minLength": 32, "maxLength": 32, "description": "The key used to verify the graph config signature when downloading from the CDN. The same key was used to create the signature in the admission webhook '/validate-config'. If the key is not set, the router will not verify the graph configuration. The key must be a 32 byte long string." } } }, "storage_providers": { "type": "object", "additionalProperties": false, "description": "The configuration for the storage providers. Storage providers can be used to provide access to persisted operations, router execution config and MCP operations.", "properties": { "cdn": { "type": "array", "items": { "type": "object", "required": ["id", "url"], "additionalProperties": false, "properties": { "id": { "type": "string", "description": "The provider ID. The provider ID is used to identify the provider in the configuration." }, "url": { "type": "string", "description": "The provider URL. The URL is used to connect to the provider.", "format": "url" } } } }, "redis": { "type": "array", "items": { "type": "object", "required": ["id", "urls"], "additionalProperties": false, "properties": { "id": { "type": "string", "description": "The provider ID. The provider ID is used to identify the provider in the configuration." }, "urls": { "type": "array", "description": "List of Redis URLs to connect to. If cluster_enabled is true, these are the seeds to discover the cluster.", "items": { "type": "string" } }, "cluster_enabled": { "type": "boolean", "description": "Whether to use the Redis Cluster client.", "default": false } } } }, "s3": { "type": "array", "description": "The configuration for the S3 storage provider. If no access key and secret key are provided, the provider will attempt to retrieve IAM credentials from the EC2 service.", "items": { "type": "object", "required": ["id", "bucket", "endpoint"], "additionalProperties": false, "properties": { "id": { "type": "string", "description": "The ID of the storage provider. The ID is used to identify the storage provider in the configuration." }, "endpoint": { "type": "string", "description": "The S3 endpoint to connect to. The endpoint is used to connect to the S3 provider. If not set, the default S3 endpoint is used." }, "access_key": { "type": "string", "description": "The access key of the S3 bucket. The access key ID is used to authenticate with the S3 bucket." }, "secret_key": { "type": "string", "description": "The secret key of the S3 bucket. The secret key is used to authenticate with the S3 bucket." }, "bucket": { "type": "string", "description": "The name of the S3 bucket. The S3 bucket is used to store the execution config." }, "region": { "type": "string", "description": "The region of the S3 bucket. The region is used to specify the region of the S3 bucket." }, "secure": { "type": "boolean", "description": "Enable the secure connection. The secure connection is used to establish a secure connection with the S3 bucket." } } } }, "file_system": { "type": "array", "description": "The file system configuration. The file system provider is used to store and retrieve data from the local file system.", "items": { "type": "object", "required": ["id", "path"], "additionalProperties": false, "properties": { "id": { "type": "string", "description": "The provider ID. The provider ID is used to identify the provider in the configuration." }, "path": { "type": "string", "description": "The file system path where data is stored and retrieved." } } } } } }, "persisted_operations": { "type": "object", "additionalProperties": false, "description": "The configuration for the persisted operations.", "properties": { "disabled": { "type": "boolean", "description": "Disable persisted operations.", "default": false }, "safelist": { "type": "object", "description": "The configuration for safelisting persisted operations.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Only allows persisted operations (sent with operation body). If the value is true, all operations not explicitly added to the safelist are blocked." } } }, "log_unknown": { "type": "boolean", "description": "Log operations (sent with the operation body) which haven't yet been persisted. If the value is true, all operations not yet persisted are logged to the router logs.", "additionalProperties": false }, "cache": { "type": "object", "additionalProperties": false, "properties": { "size": { "type": "string", "default": "100MB", "bytes": { "minimum": "10MB" }, "format": "bytes-string", "description": "The size of the cache used. The default value is 100MB." } } }, "storage": { "description": "The storage provider for persisted operation. Only one provider can be active. When no provider is specified, the router will fallback to the Cosmo CDN provider to download the persisted operations.", "required": ["provider_id"], "properties": { "provider_id": { "description": "The ID of the storage provider. The ID must match the ID of the storage provider in the storage_providers section.", "type": "string" }, "object_prefix": { "type": "string", "description": "The prefix of the object in the storage provider location. The prefix is put in front of the operation SHA256 hash. //.json" } } }, "manifest": { "type": "object", "additionalProperties": false, "description": "The configuration for the PQL manifest. When enabled, the router downloads the full persisted operations manifest from the CDN and serves operations from memory.", "properties": { "enabled": { "type": "boolean", "description": "Enable the PQL manifest feature.", "default": false }, "file_name": { "type": "string", "minLength": 1, "description": "The manifest file name. Only used when a custom storage provider is configured; ignored in CDN mode. Use a .gz or .zst extension (e.g. manifest.json.gz) to enable transparent decompression.", "default": "manifest.json" }, "poll_interval": { "type": "string", "format": "go-duration", "description": "The interval at which the router polls the CDN for manifest updates. The period is specified as a string with a number and a unit, e.g. 10s, 1m, 1h. Minimum is 10s.", "default": "10s", "duration": { "minimum": "10s" } }, "poll_jitter": { "type": "string", "format": "go-duration", "description": "The maximum random jitter added to each poll interval. The period is specified as a string with a number and a unit, e.g. 1s, 5s, 10s. Minimum is 1s.", "default": "5s", "duration": { "minimum": "1s" } }, "warmup": { "type": "object", "additionalProperties": false, "description": "Configuration for cache warmup of PQL manifest operations. When enabled, the router pre-processes all operations from the manifest on startup and after manifest updates.", "properties": { "enabled": { "type": "boolean", "description": "Enable cache warmup for PQL manifest operations.", "default": true }, "workers": { "type": "integer", "description": "The number of concurrent workers used to warm up the cache.", "default": 4, "minimum": 1 }, "items_per_second": { "type": "integer", "description": "Rate limit for items processed per second. Set to 0 for unlimited throughput.", "default": 50, "minimum": 0 }, "timeout": { "type": "string", "format": "go-duration", "description": "The maximum time allowed for the warmup to complete. The period is specified as a string with a number and a unit, e.g. 10s, 1m, 5m.", "default": "30s", "duration": { "minimum": "1s" } } } } } } } }, "automatic_persisted_queries": { "type": "object", "additionalProperties": false, "description": "The configuration for the automatic persisted queries (APQ).", "required": ["enabled"], "properties": { "enabled": { "type": "boolean", "description": "Enable automatic persisted queries." }, "cache": { "type": "object", "additionalProperties": false, "properties": { "size": { "type": "string", "default": "100MB", "bytes": { "minimum": "10MB" }, "format": "bytes-string", "description": "The size of the in-place cache used (if no external cache is designated). The default value is 100MB." }, "ttl": { "type": "integer", "default": 0, "minimum": 0, "description": "The ttl of the cache (in seconds). The ttl is used to specify the time-to-live of the cache. The default value is 0, which means that the cache never expires." } } }, "storage": { "description": "The storage provider for automatic persisted operation. Only one provider can be active. When no provider is specified, the router will use a local in-memory cache for retaining APQ queries", "required": ["provider_id", "object_prefix"], "properties": { "provider_id": { "description": "The ID of the storage provider. The ID must match the ID of the storage provider in the storage_providers section.", "type": "string" }, "object_prefix": { "type": "string", "description": "The prefix of the object in the storage provider location. The prefix is put in front of the operation SHA256 hash. //" } } } } }, "execution_config": { "type": "object", "description": "The configuration for the execution config. You can load the execution config from the local file system or from a storage provider.", "oneOf": [ { "type": "object", "additionalProperties": false, "properties": { "file": { "type": "object", "description": "The configuration for the execution config file. The config file is used to load the execution config from the local file system. The file has precedence over the storage provider.", "additionalProperties": false, "required": ["path"], "dependentSchemas": { "watch_interval": { "properties": { "watch": { "const": true } } } }, "properties": { "path": { "type": "string", "format": "file-path", "description": "The path to the execution config file. The path is used to load the execution config from the local file system." }, "watch": { "type": "boolean", "default": false, "description": "Enable the watch mode. The watch mode is used to watch the execution config file for changes. If the file changes, the router will reload the execution config without downtime." }, "watch_interval": { "type": "string", "description": "The interval at which the file is checked for changes. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "1s", "duration": { "minimum": "100ms" } } } } } }, { "type": "object", "additionalProperties": false, "properties": { "storage": { "description": "The storage provider for the execution config. Only one provider can be active. When no provider is specified, the router will fallback to the Cosmo CDN provider to download the execution config. Updating the execution config is happening in the background without downtime.", "required": ["provider_id", "object_path"], "properties": { "provider_id": { "description": "The ID of the storage provider. The ID must match the ID of the storage provider in the storage_providers section.", "type": "string" }, "object_path": { "type": "string", "description": "The path to the execution config in the storage provider. The path is used to download the execution config from the storage provider." } } } } }, { "type": "object", "additionalProperties": false, "properties": { "fallback_storage": { "description": "The fallback storage provider for the execution config in case the primary one fails.", "required": ["enabled"], "properties": { "enabled": { "type": "boolean", "description": "Enable fallback storage provider. The default value is false." }, "provider_id": { "description": "The ID of the storage provider. The ID must match the ID of the storage provider in the storage_providers section.", "type": "string" }, "object_path": { "type": "string", "description": "The path to the execution config in the storage provider. The path is used to download the execution config from the storage provider. If the path ends with `.zst` (zstd compressed) or `.gz` (gzip compressed), the file will be decompressed before reading." } } } } }, { "type": "object", "additionalProperties": false, "properties": { "manifest": { "type": "object", "description": "The configuration for loading the execution config from a manifest directory on the local file system. The manifest describes the base graph and any feature flag execution configs as separate files in a directory.", "additionalProperties": false, "required": ["path"], "dependentSchemas": { "watch_interval": { "properties": { "watch": { "const": true } } } }, "properties": { "path": { "type": "string", "format": "directory-path", "description": "The path to the manifest directory. The directory contains the manifest file and the individual execution config files referenced by it." }, "skip_missing_feature_flags": { "type": "boolean", "default": false, "description": "Skip feature flags listed in the manifest whose execution config file cannot be loaded, instead of aborting the load. Use this when occasional missing feature flag files should not prevent the router from loading the rest of the manifest." }, "ignored_feature_flags": { "type": "array", "items": { "type": "string" }, "description": "Feature flag names to skip entirely when loading the manifest. Listed flags are not loaded even when referenced by the manifest." }, "watch": { "type": "boolean", "default": false, "description": "Enable the watch mode. The watch mode is used to watch the manifest directory for changes. If a file changes, the router will reload the execution config without downtime." }, "watch_interval": { "type": "string", "description": "The interval at which the manifest directory is checked for changes. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "1s", "duration": { "minimum": "100ms" } } } } } } ] }, "split_config_poller": { "type": "object", "description": "Behavior overrides for the split-config polling strategy, which assembles the final router execution config by fetching the base graph and each feature flag config as separate files from the CDN. Only applied when the router is enrolled in split-config loading.", "additionalProperties": false, "properties": { "skip_missing_feature_flags": { "type": "boolean", "default": false, "description": "Skip feature flags that cannot be fetched instead of aborting the poll cycle. Use this when occasional feature flag fetch failures should not stop the router from picking up changes to other graphs." }, "ignored_feature_flags": { "type": "array", "items": { "type": "string" }, "description": "Feature flag names to skip entirely during config polling. Listed flags are not fetched even when present in the mapper." } } }, "graphql_metrics": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the collection of the GraphQL metrics. The default value is true." }, "collector_endpoint": { "type": "string", "description": "The endpoint to which the GraphQL metrics are collected. The endpoint is specified as a string with the format 'scheme://host:port'.", "format": "http-url" } } }, "pyroscope": { "type": "object", "additionalProperties": false, "description": "The configuration for continuous profiling with Grafana Pyroscope. When enabled, the router continuously collects profiles and sends them to the configured Pyroscope server.", "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable continuous profiling. The default value is false. When enabled, a server address must be configured." }, "server_address": { "type": "string", "format": "http-url", "description": "The address of the Pyroscope server to which the profiles are sent, e.g. your own Pyroscope or Grafana Cloud instance. Required when profiling is enabled." }, "application_name": { "type": "string", "default": "wundergraph.cosmo.router", "description": "The application name under which the profiles are stored. The default value is 'wundergraph.cosmo.router'." }, "basic_auth": { "type": "object", "additionalProperties": false, "description": "The basic authentication credentials for the Pyroscope server, e.g. for Grafana Cloud. Alternatively, use the headers option to authenticate with a bearer token.", "properties": { "username": { "type": "string", "description": "The username for basic authentication. For Grafana Cloud, this is the stack user ID." }, "password": { "type": "string", "description": "The password for basic authentication. For Grafana Cloud, this is an access token with profile write permissions." } } }, "headers": { "type": "object", "description": "The headers to send with each profile upload request. Use this to set custom authentication headers.", "additionalProperties": { "type": "string" } }, "tags": { "type": "object", "description": "The static tags to attach to all profiles. The router always attaches the hostname and the router version as tags.", "additionalProperties": { "type": "string" } }, "upload_rate": { "type": "string", "format": "go-duration", "default": "15s", "duration": { "minimum": "1s" }, "description": "The interval at which the profiles are uploaded to the Pyroscope server. The period is specified as a string with a number and a unit, e.g. 15s, 1m. The default value is 15s." }, "profile_types": { "type": "array", "description": "The profile types to collect. If not specified, the default profile types of the pyroscope client are used: cpu, alloc_objects, alloc_space, inuse_objects, inuse_space.", "default": ["cpu", "alloc_objects", "alloc_space", "inuse_objects", "inuse_space"], "items": { "type": "string", "enum": [ "cpu", "alloc_objects", "alloc_space", "inuse_objects", "inuse_space", "goroutines", "mutex_count", "mutex_duration", "block_count", "block_duration", "goroutine_leak" ] } }, "disable_gc_runs": { "type": "boolean", "default": false, "description": "Disable the automatic runtime.GC runs between collecting the heap profiles. The Go runtime only updates the heap profile data during a garbage collection cycle, so the profiler triggers a GC run before each upload to get accurate memory profiles. Set this to true if the additional GC pauses are a concern, e.g. for routers with a very large heap or strict latency requirements, at the cost of less up-to-date memory profiles. The default value is false." }, "mutex_profile_fraction": { "type": "integer", "minimum": 0, "default": 5, "description": "The fraction of mutex contention events that are reported in the mutex profile. On average 1/n events are reported. Set to 0 to disable mutex profiling. The default value is 5." }, "block_profile_rate": { "type": "integer", "minimum": 0, "default": 5, "description": "The fraction of goroutine blocking events that are reported in the blocking profile. The profiler aims to sample an average of one blocking event per n nanoseconds spent blocked. Set to 0 to disable block profiling. The default value is 5." } } }, "dev_mode": { "type": "boolean", "default": false, "description": "Enable the development mode. Development mode enables developer-focused behavior (such as pretty logs) and allows ART request options without request-token authentication." }, "tls": { "type": "object", "additionalProperties": false, "description": "The configuration for the TLS. The TLS is used to enable the TLS for the router.", "properties": { "server": { "type": "object", "description": "The configuration for the server TLS. Useful e.g. if you want to establish a secure connection from the Load-Balancer to the router.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the TLS. The default value is false." }, "cert_file": { "type": "string", "format": "file-path", "description": "The path to the certificate file. The certificate file is used to enable the TLS." }, "key_file": { "type": "string", "format": "file-path", "description": "The path to the key file. The key file is used to enable the TLS." }, "client_auth": { "type": "object", "description": "The configuration for the client authentication. The client authentication is used to authenticate the clients using the provided certificate.", "additionalProperties": false, "required": ["cert_file"], "properties": { "required": { "type": "boolean", "default": false, "description": "Require clients to present a valid certificate that is verified. The default value is false. It is recommended to enable the client authentication to enforce mutual TLS. If false and a cert is provided, the client authentication is optional but in case the client presents a certificate, it will be verified." }, "cert_file": { "type": "string", "format": "file-path", "description": "The path to the certificate file. The certificate file against which the client certificates are verified." } } } }, "if": { "properties": { "enabled": { "const": true } } }, "then": { "required": ["cert_file", "key_file"] } }, "client": { "type": "object", "description": "The TLS configuration for outbound connections from the router to subgraphs. Enables mTLS by presenting a client certificate when connecting to subgraphs.", "additionalProperties": false, "properties": { "all": { "type": "object", "description": "TLS configuration applied to all subgraph connections.", "additionalProperties": false, "properties": { "cert_file": { "type": "string", "format": "file-path", "description": "The path to the client certificate chain file. Used to authenticate the router to subgraphs. May include intermediate certificates." }, "key_file": { "type": "string", "format": "file-path", "description": "The path to the client private key file." }, "ca_file": { "type": "string", "format": "file-path", "description": "The path to the CA certificate file. Used to verify subgraph server certificates. If not set, the system's root CAs are used." }, "insecure_skip_ca_verification": { "type": "boolean", "default": false, "description": "Skip verification of the subgraph server certificate. Only use for development or testing." } }, "dependencies": { "cert_file": ["key_file"], "key_file": ["cert_file"] } }, "subgraphs": { "type": "object", "description": "Per-subgraph TLS configuration overrides. Each key is a subgraph name. Fully overrides the 'all' config for that subgraph.", "additionalProperties": { "type": "object", "additionalProperties": false, "properties": { "cert_file": { "type": "string", "format": "file-path", "description": "The path to the client certificate chain file for this subgraph. May include intermediate certificates." }, "key_file": { "type": "string", "format": "file-path", "description": "The path to the client private key file for this subgraph." }, "ca_file": { "type": "string", "format": "file-path", "description": "The path to the CA certificate file for verifying this subgraph's server certificate." }, "insecure_skip_ca_verification": { "type": "boolean", "default": false, "description": "Skip verification of this subgraph's server certificate. Only use for development or testing." } }, "dependencies": { "cert_file": ["key_file"], "key_file": ["cert_file"] } } } } }, "client_grpc": { "type": "object", "description": "The TLS configuration for outbound gRPC connections from the router to gRPC subgraphs. Enables TLS/mTLS by presenting a client certificate when connecting to gRPC subgraphs.", "additionalProperties": false, "properties": { "all": { "type": "object", "description": "TLS configuration applied to all gRPC subgraph connections.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable TLS for all gRPC subgraph connections." }, "cert_file": { "type": "string", "format": "file-path", "description": "The path to the client certificate chain file. Used to authenticate the router to gRPC subgraphs. May include intermediate certificates." }, "key_file": { "type": "string", "format": "file-path", "description": "The path to the client private key file." }, "ca_file": { "type": "string", "format": "file-path", "description": "The path to the CA certificate file. Used to verify gRPC subgraph server certificates. If not set, the system's root CAs are used." }, "insecure_skip_ca_verification": { "type": "boolean", "default": false, "description": "Skip verification of the gRPC subgraph server certificate. Only use for development or testing." } }, "required": ["enabled"], "dependencies": { "cert_file": ["key_file"], "key_file": ["cert_file"] } }, "subgraphs": { "type": "object", "description": "Per-subgraph gRPC TLS configuration overrides. Each key is a subgraph name. Fully overrides the 'all' config for that subgraph.", "additionalProperties": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable TLS for this gRPC subgraph connection." }, "cert_file": { "type": "string", "format": "file-path", "description": "The path to the client certificate chain file for this gRPC subgraph. May include intermediate certificates." }, "key_file": { "type": "string", "format": "file-path", "description": "The path to the client private key file for this gRPC subgraph." }, "ca_file": { "type": "string", "format": "file-path", "description": "The path to the CA certificate file for verifying this gRPC subgraph's server certificate." }, "insecure_skip_ca_verification": { "type": "boolean", "default": false, "description": "Skip verification of this gRPC subgraph's server certificate. Only use for development or testing." } }, "required": ["enabled"], "dependencies": { "cert_file": ["key_file"], "key_file": ["cert_file"] } } } } } } }, "websocket": { "type": "object", "description": "The configuration for the WebSocket transport. The WebSocket transport is used to enable the WebSocket transport for the GraphQL subscriptions.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "description": "Enable WebSocket transport. The default value is true." }, "absinthe_protocol": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "description": "Enable Absinthe protocol. The default value is true." }, "handler_path": { "type": "string", "default": "/absinthe/socket", "description": "The path to mount the Absinthe Protocol Handler on. The default value is '/absinthe/socket'." } } }, "forward_upgrade_headers": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "description": "Forward upgrade request headers in the extensions payload when starting a subscription on a Subgraph. The default value is true." }, "allow_list": { "type": "array", "description": "The names of the headers to forward. The default value is 'Authorization'.", "default": ["Authorization"], "items": { "type": "string" } } } }, "forward_upgrade_query_params": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Forward upgrade request query parameters in the extensions payload when starting a subscription on a Subgraph. The default value is true." }, "allow_list": { "type": "array", "description": "The names of the query parameters to forward. The default value is 'Authorization'.", "default": ["Authorization"], "items": { "type": "string" } } } }, "forward_initial_payload": { "type": "boolean", "default": true, "description": "Forward the initial payload in the extensions payload when starting a subscription on a Subgraph. The default value is true." }, "authentication": { "type": "object", "description": "The configuration used to authenticate the WebSocket connections.", "additionalProperties": false, "properties": { "from_initial_payload": { "type": "object", "description": "The configuration used to tell the Router to look for the JWT (JSON Web Token) in the initial payload of the WebSocket Connection.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "This configuration indicates if the Router should look for the JWT (JSON Web Token) in the initial payload of the WebSocket Connection. The default value is 'false'.", "default": false }, "key": { "type": "string", "default": "Authorization", "description": "The name of the property holding the JWT (JSON Web Token) value. The default value is 'Authorization'" }, "export_token": { "type": "object", "description": "The configuration responsible for exporting the JWT (JSON Web Token) to the client's request header. If the specified header key differs from the default value, 'Authorization', it needs to be included in the 'forward_upgrade_headers' list to ensure it is forwarded to the subgraphs.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "This configuration indicates if the Router will export the JWT (JSON Web Token) to the client request header. The default value is 'false'.", "default": true }, "header_key": { "type": "string", "description": "The name of the header property that will have the JWT (JSON Web Token) value. The default value is 'Authorization'", "default": "Authorization" } } } } } } }, "client_info_from_initial_payload": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "This configuration indicates if the Router should set the client info from the initial payload of the WebSocket Connection. The default value is 'false'.", "default": true }, "name_field": { "type": "string", "description": "The name of the field in the initial payload that will have the client name. The default value is 'graphql-client-name'.", "default": "graphql-client-name" }, "version_field": { "type": "string", "description": "The name of the field in the initial payload that will have the client version. The default value is 'graphql-client-version'.", "default": "graphql-client-version" }, "forward_to_request_headers": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "This configuration indicates if the Router should forward the client info to the request headers. The default value is 'false'.", "default": true }, "name_target_header": { "type": "string", "description": "The name of the header property that will have the client name. The default value is 'graphql-client-name'.", "default": "graphql-client-name" }, "version_target_header": { "type": "string", "description": "The name of the header property that will have the client version. The default value is 'graphql-client-version'.", "default": "graphql-client-version" } } } } } } }, "compliance": { "type": "object", "description": "The configuration for the compliance. Includes for example the configuration for the anonymization of the IP addresses.", "additionalProperties": false, "properties": { "anonymize_ip": { "type": "object", "description": "The configuration for the anonymization of the IP addresses. Redaction is applied to the IP addresses in the traces and logs to protect the privacy of the users.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the anonymization of the IP addresses. The default value is true." }, "method": { "type": "string", "default": "redact", "description": "The method used to anonymize the IP addresses. The supported methods are 'redact' and 'hash'. The default value is 'redact'. The 'redact' method replaces the IP addresses with the string '[REDACTED]'. The 'hash' method hashes the IP addresses using the SHA-256 algorithm.", "enum": ["redact", "hash"] } } } } }, "batching": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the batching. The batching is used to batch an incoming query array in a request. The default value is false.", "default": false }, "max_concurrency": { "type": "integer", "description": "The maximum number of batches that can be processed concurrently", "default": 10, "minimum": 1 }, "max_entries_per_batch": { "type": "integer", "description": "The maximum number of entries allowed in a batch", "default": 100, "minimum": 1 }, "omit_extensions": { "type": "boolean", "description": "omit extensions on any batch processing errors", "default": false } } }, "access_logs": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the access logs. The access logs are used to log the incoming requests. By default, the access logs are enabled and logged to the standard output.", "default": true }, "level": { "type": "string", "enum": ["debug", "info", "warn", "error", "panic", "fatal"], "description": "The log level for access logs. The log level is used to control the verbosity of the access logs. The default value is 'info'.", "default": "info" }, "add_stacktrace": { "type": "boolean", "description": "Add stack traces to access logs when enabled for all error logs. When disabled, panic error logs will still contain stack traces. The default value is false.", "default": true }, "buffer": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the buffer. The buffer is used to buffer the logs before writing them to the output. The default value is false." }, "flush_interval": { "type": "string", "description": "The interval at which the buffer is flushed. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "10s", "duration": { "minimum": "100ms", "maximum": "1m" } }, "size": { "type": "string", "default": "256KB", "bytes": { "minimum": "1KB" }, "format": "bytes-string", "description": "The size of the buffer. The default value is 256KB." } } }, "output": { "type": "object", "description": "The log destination. The supported destinations are stdout and file. Only one option can be enabled. The destination is stdout.", "additionalProperties": false, "properties": { "stdout": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean" } } }, "file": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean" }, "path": { "type": "string", "description": "The path to the log file. The path is used to specify the path to the log file." }, "mode": { "type": "string", "description": "The file mode (permissions) for the log file as an octal string. Must be exactly 3 octal digits (0-7), optionally prefixed with '0' (e.g., '640', '0640', '755', '0755'). The default value is '0640'.", "default": "0640", "pattern": "^0?[0-7]{3}$" } } } } }, "router": { "type": "object", "additionalProperties": false, "description": "The configuration for the router access logs", "properties": { "fields": { "$ref": "#/$defs/context_fields" }, "ignore_query_params_list": { "type": "array", "description": "List of query params to be ignored from being logged in the query field.", "default": ["variables"], "items": { "type": "string" } } } }, "subgraphs": { "type": "object", "additionalProperties": false, "description": "The configuration for the subgraph access logs", "properties": { "enabled": { "type": "boolean", "description": "Enable the subgraph access logs.", "default": false }, "fields": { "allOf": [ { "$ref": "#/$defs/context_fields" }, { "items": { "properties": { "value_from": { "properties": { "context_field": { "enum": [ "operation_name", "operation_type", "operation_hash", "persisted_operation_sha256", "operation_sha256", "operation_parsing_time", "operation_validation_time", "operation_planning_time", "operation_normalization_time", "request_error", "response_error_message" ] }, "expression": { "type": "string", "description": "The name of the request header from which to extract the value." } } } } } } ] } } } } }, "telemetry": { "type": "object", "description": "The configuration for the telemetry. The telemetry is used to collect and export the traces and metrics.", "additionalProperties": false, "properties": { "service_name": { "type": "string", "description": "The name of the service. The name is used to identify the service in the traces and metrics. The default value is 'cosmo-router'.", "default": "cosmo-router" }, "resource_attributes": { "type": "array", "description": "The resource attributes to add to OTEL metrics and traces. The resource attributes identify the entity producing the traces and metrics. Because Prometheus metrics rely on the OpenTelemetry metrics, the resource attributes are also added to the Prometheus target_info metric.", "items": { "type": "object", "additionalProperties": false, "required": ["key", "value"], "properties": { "key": { "type": "string", "description": "The key of the attribute." }, "value": { "type": "string", "description": "The value of the attribute." } } } }, "attributes": { "type": "array", "description": "The default attributes to add to OTEL and Prometheus metrics. Because Prometheus metrics rely on the OpenTelemetry metrics, the attributes are also added to the Prometheus metrics.", "items": { "type": "object", "description": "The configuration for custom attributes. Custom attributes can be created from request headers or static values. Keep in mind, that every new custom attribute increases the cardinality of the pipeline.", "additionalProperties": false, "required": ["key"], "properties": { "key": { "type": "string", "description": "The key of the field." }, "default": { "type": "string", "description": "The default value of the field. If the value is not set, value_from is used. If both value and value_from are set, value_from has precedence and in case of a missing value_from, the default value is used." }, "value_from": { "type": "object", "description": "Defines a source for the field value e.g. from a request header. If both default and value_from are set, value_from has precedence.", "additionalProperties": false, "properties": { "request_header": { "type": "string", "description": "The name of the request header from which to extract the value. The value is only extracted when a request context is available otherwise the default value is used." }, "expression": { "type": "string", "description": "The name of the request header from which to extract the value. The value is only extracted when a request context is available otherwise the default value is used." } }, "oneOf": [ { "required": ["request_header"] }, { "required": ["expression"] } ] } } } }, "tracing": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false }, "sampling_rate": { "type": "number", "description": "The sampling rate for the traces. The value must be between 0 and 1. If the value is 0, no traces will be sampled. If the value is 1, all traces will be sampled. The default value is 1.", "default": 1, "minimum": 0, "maximum": 1 }, "parent_based_sampler": { "type": "boolean", "default": true, "description": "Enable the parent-based sampler. The parent-based sampler is used to sample the traces based on the parent trace. The default value is true." }, "export_graphql_variables": { "type": "boolean", "default": false, "description": "Enable the export of the GraphQL variables. The GraphQL variables are exported with the traces. The default value is false to avoid leaking sensitive information." }, "with_new_root": { "type": "boolean", "default": false, "description": "Specifies that the router span should be treated as a root Span. Any existing parent span context will be ignored when defining the Span's trace identifiers. This is useful when the router must be the entry point of the trace." }, "operation_content_attributes": { "type": "boolean", "default": false, "description": "Enable the addition of GraphQL operation body content as trace attributes. When enabled, original operation content will be added to the trace span for parse and normalized operation content will be added to the trace span for normalize. The default value is false." }, "exporters": { "type": "array", "description": "The exporters to use to export the traces. If no exporters are specified, the default Cosmo Cloud exporter is used. If you override, please make sure to include the default exporter.", "items": { "type": "object", "required": ["endpoint"], "additionalProperties": false, "properties": { "disabled": { "type": "boolean" }, "exporter": { "type": "string", "description": "The exporter to use for the traces. The supported exporters are 'http' and 'grpc'.", "default": "http", "enum": ["http", "grpc"] }, "endpoint": { "type": "string" }, "path": { "type": "string", "description": "The path to which the traces are exported.", "default": "/v1/traces", "format": "x-uri" }, "headers": { "type": "object", "additionalProperties": { "type": "string" } }, "batch_timeout": { "type": "string", "description": "The maximum time to wait before exporting the traces. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "10s", "duration": { "minimum": "5s", "maximum": "2m" } }, "export_timeout": { "type": "string", "description": "The maximum time to wait for the export to complete. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "30s", "duration": { "minimum": "5s", "maximum": "2m" } } } } }, "propagation": { "type": "object", "additionalProperties": false, "properties": { "trace_context": { "type": "boolean", "description": "Enable the trace context propagation. See https://www.w3.org/TR/trace-context/ for more information." }, "jaeger": { "type": "boolean", "description": "Enable the Jaeger propagation. See https://www.jaegertracing.io/ (compliant with opentracing) for more information." }, "b3": { "type": "boolean", "description": "Enable the B3 propagation. See https://github.com/openzipkin/b3-propagation (zipkin) for more information." }, "datadog": { "type": "boolean", "description": "Enable the Datadog propagation." }, "baggage": { "type": "boolean", "description": "Enable the baggage propagation. See https://www.w3.org/TR/baggage/ for more information." } } }, "response_trace_id": { "type": "object", "description": "The configuration to expose the trace_id through a response header.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enables the addition of trace_id to the response header." }, "header_name": { "type": "string", "default": "x-wg-trace-id", "description": "The name of the header which the holds the trace_id. The default value is x-wg-trace-id." } } }, "attributes": { "type": "array", "description": "Custom span attributes for subgraphs", "items": { "type": "object", "description": "The configuration for custom span attributes for subgraph tracing.", "additionalProperties": false, "required": ["key"], "properties": { "key": { "type": "string", "description": "The key of the field." }, "value_from": { "type": "object", "description": "Defines a source for the field value e.g. from a request header. If both default and value_from are set, value_from has precedence.", "additionalProperties": false, "properties": { "expression": { "type": "string", "description": "The name of the request header from which to extract the value. The value is only extracted when a request context is available otherwise the default value is used." } }, "oneOf": [ { "required": ["expression"] } ] } } } }, "sanitize_utf8": { "type": "object", "description": "Configuration for sanitizing invalid UTF-8 sequences in span attribute values.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the sanitization of invalid UTF-8 sequences in span attribute values. Invalid sequences are replaced with the Unicode replacement character (U+FFFD)." }, "log_sanitizations": { "type": "boolean", "default": false, "description": "Log a warning when invalid UTF-8 sequences are sanitized. The log includes the attribute key and original value." } } } } }, "metrics": { "type": "object", "description": "The configuration for the collection and export of metrics. The metrics are collected and exported using the OpenTelemetry protocol (OTLP) and Prometheus.", "additionalProperties": false, "properties": { "experiment_cardinality_limit": { "type": "integer", "description": "Sets a hard limit on the number of Metric Points that can be collected during a collection cycle. NOTE: This option is experimental and may change in future versions.", "minimum": 1, "default": 2000 }, "attributes": { "type": "array", "description": "The attributes to add to OTLP Metrics and Prometheus.", "items": { "type": "object", "description": "The configuration for custom attributes. Custom attributes can be created from request headers, static values or context fields. Not every context fields are available at all request life-cycle stages. If a value is a list, the value is JSON encoded for OTLP. For Prometheus, the values are exploded into multiple metrics with unique labels. Keep in mind, that every new custom attribute increases the cardinality.", "additionalProperties": false, "required": ["key"], "properties": { "key": { "type": "string", "description": "The key of the field." }, "default": { "type": "string", "description": "The default value of the field. If the value is not set, value_from is used. If both value and value_from are set, value_from has precedence and in case of a missing value_from, the default value is used." }, "value_from": { "type": "object", "description": "Defines a source for the field value e.g. from a request header or request context. If both default and value_from are set, value_from has precedence.", "additionalProperties": false, "properties": { "request_header": { "type": "string", "description": "The name of the request header from which to extract the value. The value is only extracted when a request context is available otherwise the default value is used." }, "context_field": { "type": "string", "description": "The field name of the context from which to extract the value. The value is only extracted when a context is available otherwise the default value is used.", "enum": [ "operation_service_names", "graphql_error_codes", "graphql_error_service_names", "operation_sha256", "operation_name", "operation_hash", "router_config_version" ] } } } } } }, "otlp": { "type": "object", "description": "The configuration for the OpenTelemetry protocol (OTLP). The OTLP is used to collect and export the metrics.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "description": "Enable the collection of metrics." }, "router_runtime": { "type": "boolean", "default": true, "description": "Enable the collection of metrics for the router runtime." }, "graphql_cache": { "type": "boolean", "default": false, "description": "Enable the collection of metrics for the GraphQL operation router caches. The default value is false." }, "connection_stats": { "type": "boolean", "default": false, "description": "Enable the collection of connection stats. The default value is false." }, "network": { "type": "object", "additionalProperties": false, "description": "Configure additional network metrics.", "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable per-request subgraph HTTP phase metrics, including DNS lookup, TCP connect, TLS handshake, time-to-first-request-byte, and time-to-first-byte histograms. The default value is false." } } }, "resolver": { "type": "object", "additionalProperties": false, "description": "Configure additional resolver metrics.", "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable resolver metrics, including resolver concurrency gauges and resolver acquire duration histograms. The default value is false." } } }, "streams": { "type": "boolean", "default": false, "description": "Enable the collection of stream metrics. This contains metrics related to EDFS. The default value is false." }, "circuit_breaker": { "type": "boolean", "default": false, "description": "Enable the collection of circuit breaker stats. The default value is false." }, "engine_stats": { "type": "object", "additionalProperties": false, "properties": { "subscriptions": { "type": "boolean", "default": false, "description": "Enabling this will report additional engine metrics for WebSockets and SSE such as connections, subscriptions and triggers. The default value is false" } } }, "cost_stats": { "type": "object", "additionalProperties": false, "description": "Configure cost statistics for OTLP metrics.", "properties": { "estimated_enabled": { "type": "boolean", "default": false, "description": "Enable the collection of estimated cost stats. The default value is false." }, "actual_enabled": { "type": "boolean", "default": false, "description": "Enable the collection of actual cost stats. The default value is false." } } }, "exporters": { "type": "array", "description": "The exporters to use to export the metrics. If no exporters are specified, the default Cosmo Cloud exporter is used. If you override, please make sure to include the default exporter.", "items": { "type": "object", "additionalProperties": false, "properties": { "disabled": { "type": "boolean" }, "exporter": { "type": "string", "description": "The exporter protocol to use to export metrics. The supported exporters are 'http' and 'grpc'.", "default": "http", "enum": ["http", "grpc"] }, "endpoint": { "type": "string", "description": "The endpoint to which the metrics are exported." }, "path": { "type": "string", "description": "The path to which the metrics are exported. This is ignored when using 'grpc' as exporter and can be omitted.", "default": "/v1/metrics", "format": "x-uri" }, "headers": { "type": "object", "description": "The headers to send with the request. Use this to set the authentication headers.", "additionalProperties": { "type": "string" } }, "temporality": { "type": "string", "description": "Temporality defines the window that an aggregation is calculated over.", "enum": ["delta", "cumulative"] } }, "required": ["exporter", "endpoint"] } }, "exclude_metrics": { "type": "array", "description": "The metrics to exclude from the OTEL metrics. Accepts a list of Go regular expressions. Use https://regex101.com/ to test your regular expressions.", "items": { "type": "string" } }, "exclude_metric_labels": { "type": "array", "description": "The metric labels to exclude from the OTEL metrics. Accepts a list of Go regular expressions. Use https://regex101.com/ to test your regular expressions.", "items": { "type": "string" } }, "log_exporter": { "type": "object", "description": "Log exporter. When enabled, logs all collected metrics via the router's logger at each export interval.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enables the log exporter. The default value is false." }, "exclude_metrics": { "type": "array", "description": "List of regex patterns for metric names to exclude from log output. Cannot be used together with include_metrics.", "items": { "type": "string" } }, "include_metrics": { "type": "array", "description": "List of regex patterns for metric names to include in log output. Only matching metrics will be logged. Cannot be used together with exclude_metrics.", "items": { "type": "string" } } }, "not": { "required": ["exclude_metrics", "include_metrics"] } }, "exemplar_filter": { "type": "string", "default": "always_off", "enum": ["trace_based", "always_off", "always_on"], "description": "Controls which metric measurements are eligible to record exemplars. 'always_off' records no exemplars (the default). 'trace_based' only records exemplars for measurements taken within a sampled trace context. 'always_on' records exemplars for all measurements. See https://opentelemetry.io/docs/specs/otel/metrics/sdk/#exemplarfilter." } } }, "prometheus": { "type": "object", "description": "The configuration for the Prometheus metrics. The Prometheus metrics are used to collect and export the metrics.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true }, "path": { "type": "string", "description": "The path to which the metrics are served.", "format": "x-uri", "default": "/metrics" }, "listen_addr": { "type": "string", "description": "The address on which the metrics are served.", "format": "hostname-port", "default": "localhost:8088" }, "graphql_cache": { "type": "boolean", "default": false, "description": "Enable the collection of metrics for the GraphQL operation router caches. The default value is false." }, "connection_stats": { "type": "boolean", "default": false, "description": "Enable the collection of connection stats. The default value is false." }, "network": { "type": "object", "additionalProperties": false, "description": "Configure additional network metrics.", "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable per-request subgraph HTTP phase metrics, including DNS lookup, TCP connect, TLS handshake, time-to-first-request-byte, and time-to-first-byte histograms. The default value is false." } } }, "resolver": { "type": "object", "additionalProperties": false, "description": "Configure additional resolver metrics.", "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable resolver metrics, including resolver concurrency gauges and resolver acquire duration histograms. The default value is false." } } }, "streams": { "type": "boolean", "default": false, "description": "Enable the collection of stream metrics. This contains metrics related to EDFS. The default value is false." }, "circuit_breaker": { "type": "boolean", "default": false, "description": "Enable the collection of circuit breaker stats. The default value is false." }, "engine_stats": { "type": "object", "additionalProperties": false, "properties": { "subscriptions": { "type": "boolean", "default": false, "description": "Enabling this will report additional engine metrics for WebSockets and SSE such as connections, subscriptions and triggers. The default value is false" } } }, "cost_stats": { "type": "object", "additionalProperties": false, "description": "Configure cost statistics for Prometheus metrics.", "properties": { "estimated_enabled": { "type": "boolean", "default": false, "description": "Enable the collection of estimated cost stats. The default value is false." }, "actual_enabled": { "type": "boolean", "default": false, "description": "Enable the collection of actual cost stats. The default value is false." } } }, "exclude_metrics": { "type": "array", "description": "The metrics to exclude from the Prometheus metrics. Accepts a list of Go regular expressions. Use https://regex101.com/ to test your regular expressions.", "items": { "type": "string" } }, "exclude_metric_labels": { "type": "array", "description": "The metric labels to exclude from the Prometheus metrics. Accepts a list of Go regular expressions. Use https://regex101.com/ to test your regular expressions.", "items": { "type": "string" } }, "exclude_scope_info": { "type": "boolean", "default": false, "description": "Exclude scope info from Prometheus metrics. The default value is false." }, "schema_usage": { "type": "object", "description": "Configure schema field usage metrics for Prometheus", "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the collection and export of GraphQL schema metrics to Prometheus. The default value is false." }, "include_operation_sha": { "type": "boolean", "default": false, "description": "Include the operation SHA256 in the metric labels, this can be an expensive operation. The default value is false." }, "exporter": { "type": "object", "description": "Configuration for the schema usage exporter", "properties": { "batch_size": { "type": "integer", "default": 4096, "minimum": 1, "description": "The maximum number of schema usage items to be applied in a single batch. The default value is 4096." }, "queue_size": { "type": "integer", "default": 12800, "minimum": 1, "description": "The maximum number of schema usage items allowed in queue at a given time. The default value is 12800." }, "interval": { "type": "string", "default": "2s", "duration": { "minimum": "100ms" }, "description": "The interval at which the schema usage queue is flushed. The period is specified as a string with a number and a unit, e.g. 10s, 1m. The supported units are 's', 'm', 'h'." }, "export_timeout": { "type": "string", "default": "10s", "duration": { "minimum": "1s" }, "description": "The timeout for the schema usage export. The period is specified as a string with a number and a unit, e.g. 10s, 1m. The supported units are 's', 'm', 'h'." } } } } }, "exemplar_filter": { "type": "string", "default": "always_off", "enum": ["trace_based", "always_off", "always_on"], "description": "Controls which metric measurements are eligible to record exemplars. 'always_off' records no exemplars (the default). 'trace_based' only records exemplars for measurements taken within a sampled trace context. 'always_on' records exemplars for all measurements. See https://opentelemetry.io/docs/specs/otel/metrics/sdk/#exemplarfilter." } } } } } } }, "cors": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Set this to enable/disable the CORS middleware. It is enabled by default. When disabled, the rest of the properties for CORS have no effect.", "default": true }, "allow_origins": { "type": "array", "description": "The allowed origins. The default value is to allow all origins. The value can be a list of origins or the wildcard '*'.", "default": ["*"], "items": { "type": "string" } }, "allow_methods": { "type": "array", "default": ["GET", "POST", "HEAD"], "description": "The allowed HTTP methods. The default value is to allow the methods 'GET', 'POST', and 'HEAD'.", "items": { "type": "string", "enum": ["GET", "POST", "HEAD", "PUT", "DELETE", "PATCH", "OPTIONS"] } }, "allow_headers": { "type": "array", "description": "The allowed HTTP headers. The default value is to allow all headers. Default headers are always appended to the list of allowed headers.", "default": [ "Origin", "Content-Length", "Content-Type", "Authorization", "Origin", "Content-Length", "Content-Type", "Graphql-Client-Name", "Graphql-Client-Version", "ApolloGraphql-Client-Name", "ApolloGraphql-Client-Version", "x-wg-trace", "x-wg-disable-tracing", "x-wg-token", "x-wg-include-query-plan", "x-wg-skip-loader", "traceparent", "tracestate" ], "items": { "type": "string" } }, "allow_credentials": { "type": "boolean", "default": true, "description": "The allowed credentials. The default value is to allow credentials. This allows the browser to send cookies and authentication headers." }, "max_age": { "type": "string", "duration": { "minimum": "5m" }, "default": "5m", "description": "The maximum age of the preflight request. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." } } }, "cluster": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The name of the cluster. This is used to identify the cluster in the control plane and in the metrics." } } }, "listen_addr": { "type": "string", "description": "The address on which the router listens for incoming requests. The address is specified as a string with the format 'host:port'.", "default": "localhost:3002", "format": "hostname-port" }, "controlplane_url": { "type": "string", "description": "The URL of the control plane. The URL is used to register the router on the control-plane. The URL is specified as a string with the format 'scheme://host:port'.", "default": "https://cosmo-cp.wundergraph.com", "format": "uri", "pattern": "^https?://" }, "playground": { "type": "object", "description": "The configuration for the playground. The playground is a web-based GraphQL IDE that allows you to interact with the GraphQL API.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the GraphQL Playground. The GraphQL Playground is a web-based GraphQL IDE that allows you to interact with the GraphQL API. The default value is true. If the value is false, the GraphQL Playground is disabled.", "default": true }, "path": { "type": "string", "format": "x-uri", "default": "/", "description": "The path of the GraphQL Playground. The GraphQL Playground is a web-based GraphQL IDE that allows you to interact with the GraphQL API. The default value is '/'." }, "concurrency_limit": { "type": "integer", "description": "The concurrency limit for loading the playground. This shouldn't impact normal usage.", "default": 10, "minimum": 1 } } }, "playground_enabled": { "type": "boolean", "description": "Enable the GraphQL Playground. The GraphQL Playground is a web-based GraphQL IDE that allows you to interact with the GraphQL API. The default value is true. If the value is false, the GraphQL Playground is disabled.", "default": true, "deprecated": true, "deprecationMessage": "This option is deprecated. Please use the playground.enabled configuration instead." }, "introspection_enabled": { "type": "boolean", "description": "Enable the GraphQL introspection. The GraphQL introspection allows you to query the schema of the GraphQL API. The default value is true. If the value is false, the GraphQL introspection is disabled. In production, it is recommended to disable the introspection.", "default": true, "deprecated": true, "deprecationMessage": "This option is deprecated. Please use the introspection.enabled configuration instead." }, "introspection": { "type": "object", "description": "", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the GraphQL introspection. The GraphQL introspection allows you to query the schema of the GraphQL API. The default value is true. If the value is false, the GraphQL introspection is disabled. In production, it is recommended to disable the introspection.", "default": true }, "secret": { "type": "string", "description": "A dedicated secret to protect introspection when skipping standard authentication. Needs to be passed via the 'Authorization' header. Effective only when /authentication/ignore_introspection is true.", "minLength": 32 } } }, "query_plans_enabled": { "type": "boolean", "description": "Query plans can be very useful for debugging and understand the query execution. By default, query plans are enabled, but they are still only accessible if a request is signed (from Cosmo Studio) or in dev mode, which is relatively secure. If you want to disable query plans completely, set this to false.", "default": true }, "log_level": { "type": "string", "enum": ["debug", "info", "warn", "error", "panic", "fatal"], "description": "The log level. The log level is used to control the verbosity of the logs. The default value is 'info'.", "default": "info" }, "json_log": { "type": "boolean", "description": "Enable the JSON log format. The JSON log format is used to log the logs in JSON format. The default value is true. If the value is false, the logs are logged a human friendly text format.", "default": true }, "log_service_name": { "type": "string", "description": "The service name used in the 'service' field of log entries. The default value is '@wundergraph/router'.", "default": "@wundergraph/router" }, "shutdown_delay": { "type": "string", "duration": { "minimum": "15s" }, "description": "The delay before the router shuts down. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "60s" }, "grace_period": { "type": "string", "format": "go-duration", "description": "The grace period before the router shuts down. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "20s" }, "poll_interval": { "type": "string", "description": "The interval at which the router polls the CDN for updates. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "10s", "duration": { "minimum": "5s" } }, "poll_jitter": { "type": "string", "description": "A duration maximum for jitter added to the polling interval. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "5s", "duration": { "minimum": "0s" } }, "health_check_path": { "type": "string", "default": "/health", "format": "x-uri", "description": "The path of the health check endpoint. The health check endpoint is used to check the health of the router. The default value is '/health'." }, "readiness_check_path": { "type": "string", "default": "/health/ready", "format": "x-uri", "description": "The path of the readiness check endpoint. The readiness check endpoint is used to check the readiness of the router. The default value is '/health/ready'." }, "liveness_check_path": { "type": "string", "default": "/health/live", "format": "x-uri", "description": "The path of the liveness check endpoint. The liveness check endpoint is used to check the liveness of the router. The default value is '/health/live'." }, "graphql_path": { "type": "string", "default": "/graphql", "format": "x-uri", "description": "The path of the GraphQL endpoint. The GraphQL endpoint is used to send the GraphQL queries, subscriptions and mutations. The default value is '/graphql'." }, "playground_path": { "type": "string", "format": "x-uri", "default": "/", "description": "The path of the GraphQL Playground. The GraphQL Playground is a web-based GraphQL IDE that allows you to interact with the GraphQL API. The default value is '/'.", "deprecated": true, "deprecationMessage": "playground_path is deprecated. Please use the playground.path configuration instead." }, "file_upload": { "type": "object", "description": "The configuration for file upload. Configure whether it should be enabled along with file size and number of files.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true }, "max_file_size": { "type": "string", "bytes": { "minimum": "1MB" }, "description": "The maximum size of a file that can be uploaded. The size is specified as a string with a number and a unit, e.g. 10KB, 1MB, 1GB. The supported units are 'KB', 'MB', 'GB'." }, "max_files": { "type": "integer", "default": 10, "minimum": 1, "description": "The maximum number of files that can be uploaded." } } }, "traffic_shaping": { "type": "object", "description": "The configuration for the traffic shaping. Configure rules for traffic shaping like maximum request body size, timeouts, retry behavior, etc. See https://cosmo-docs.wundergraph.com/router/traffic-shaping for more information.", "additionalProperties": false, "properties": { "router": { "type": "object", "additionalProperties": false, "properties": { "max_request_body_size": { "type": "string", "bytes": { "minimum": "1MB" }, "description": "The maximum request body size. The size is specified as a string with a number and a unit, e.g. 10KB, 1MB, 1GB. The supported units are 'KB', 'MB', 'GB'." }, "max_header_bytes": { "type": "string", "description": "The maximum size of the request headers. Setting this to 0 uses the default value from the http standard lib, which is 1MiB.", "default": "0MiB", "bytes": {} }, "decompression_enabled": { "type": "boolean", "description": "When enabled, the router will check incoming requests for a 'Content-Encoding' header and decompress the body accordingly. Currently only gzip is supported", "default": true }, "response_compression_min_size": { "type": "string", "format": "bytes-string", "description": "The minimum size of the response body in bytes to enable response compression. The size is specified as a string with a number and a unit, e.g. 4KiB, 10KB, 1MB", "default": "4KiB", "bytes": { "minimum": "1B" } } } }, "all": { "type": "object", "description": "The configuration for all subgraphs. The configuration is used to configure the traffic shaping for all subgraphs.", "$ref": "#/$defs/traffic_shaping_subgraph_request_rule" }, "subgraphs": { "type": "object", "description": "The configuration to control traffic shaping for specific subgraphs.", "additionalProperties": { "$ref": "#/$defs/traffic_shaping_subgraph_request_rule" } } } }, "headers": { "type": "object", "description": "The configuration for the headers. The headers rules are used to modify the headers of the incoming requests and how they are propagated to your subgraphs. See https://cosmo-docs.wundergraph.com/router/proxy-capabilities#forward-http-headers-to-subgraphs for more information.", "additionalProperties": false, "properties": { "all": { "additionalProperties": false, "properties": { "request": { "type": "array", "items": { "oneOf": [ { "$ref": "#/$defs/traffic_shaping_header_rule" }, { "$ref": "#/$defs/set_header_rule" } ] } }, "response": { "type": "array", "items": { "oneOf": [ { "$ref": "#/$defs/traffic_shaping_header_response_rule" }, { "$ref": "#/$defs/set_response_header_rule" } ] } } } }, "subgraphs": { "type": "object", "additionalProperties": { "type": "object", "additionalProperties": false, "properties": { "request": { "type": "array", "items": { "oneOf": [ { "$ref": "#/$defs/traffic_shaping_header_rule" }, { "$ref": "#/$defs/set_header_rule" } ] } }, "response": { "type": "array", "items": { "oneOf": [ { "$ref": "#/$defs/traffic_shaping_header_response_rule" }, { "$ref": "#/$defs/set_header_rule" } ] } } } } }, "cookie_whitelist": { "type": "array", "description": "A list of Cookie keys allowed to be forwarded to the subgraph. If the list is empty or unspecified, all cookies are forwarded. This option will do nothing if the 'Cookie' header is not propagated.", "default": [], "items": { "type": "string" } }, "router": { "type": "object", "properties": { "response": { "type": "array", "description": "A list of header rules to apply to router responses.", "items": { "$ref": "#/$defs/router_response_header_rule" } } } } } }, "cache_control_policy": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Determines whether cache control policy is enabled.", "examples": [true] }, "value": { "type": "string", "description": "Global cache control value.", "examples": ["max-age=180, public"] }, "subgraphs": { "type": "array", "description": "Subgraph-specific cache control settings.", "required": ["name"], "additionalProperties": false, "items": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the subgraph.", "examples": ["products"] }, "value": { "type": "string", "description": "Cache control value for the subgraph.", "examples": ["max-age=60, public"] } } } } }, "required": ["enabled"], "additionalProperties": false }, "modules": { "type": "object", "description": "The configuration for the modules. The modules are used to extend the functionality of the router. The modules are specified as a map of module names to module configurations. It needs to match with the name of the module and the configuration of the module. See https://cosmo-docs.wundergraph.com/router/custom-modules for more information.", "additionalProperties": { "type": "object", "description": "The configuration for the module. The key is the name of the module specified in the code.", "additionalProperties": true } }, "authentication": { "type": "object", "description": "The configuration for the authentication. The authentication is used to authenticate the incoming requests. We currently support JWK (JSON Web Key) authentication.", "additionalProperties": false, "properties": { "jwt": { "type": "object", "additionalProperties": false, "properties": { "jwks": { "type": "array", "additionalProperties": false, "items": { "type": "object", "additionalProperties": false, "properties": { "url": { "type": "string", "description": "The URL of the JWKs. The JWKs are used to verify the JWT (JSON Web Token). The URL is specified as a string with the format 'scheme://host:port'.", "format": "http-url" }, "audiences": { "type": "array", "description": "The audiences of the JWKs. The audiences are used to verify the JWT (JSON Web Token). The audiences are specified as a list of strings.", "items": { "type": "string" } }, "secret": { "type": "string", "description": "The secret of the JWKs" }, "symmetric_algorithm": { "type": "string", "description": "The symmetric algorithm used", "enum": ["HS256", "HS384", "HS512"] }, "header_key_id": { "type": "string", "description": "The KID header of the JWK token created using the secret" }, "allowed_use": { "type": "array", "description": "The allowed value of the use parameter for the JWKs. If not specified, only keys with use set to 'sig' will be used. If your server provides no use, you can add an empty value to allow those keys.", "default": ["sig"], "items": { "type": "string", "enum": ["sig", "enc", ""] } }, "algorithms": { "type": "array", "description": "The allowed algorithms for the keys that are retrieved from the JWKs. An empty list means that all algorithms are allowed.", "items": { "type": "string", "enum": [ "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "EdDSA" ] } }, "refresh_interval": { "type": "string", "duration": { "minimum": "5s" }, "description": "The interval at which the JWKs are refreshed. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "1m" }, "refresh_unknown_kid": { "type": "object", "description": "Controls rate-limited refresh behavior when a JWT KID is unknown.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable refresh attempts on unknown KID.", "default": false }, "max_wait": { "type": "string", "description": "Maximum time to wait for a refresh permit before giving up.", "default": "2m", "duration": { "minimum": "0s" } }, "interval": { "type": "string", "description": "Token refill interval for the rate limiter.", "default": "30s", "duration": { "minimum": "1s" } }, "burst": { "type": "integer", "description": "Burst size for the rate limiter.", "default": 2, "minimum": 1 } } } }, "oneOf": [ { "required": ["url"], "not": { "anyOf": [ { "required": ["secret"] }, { "required": ["symmetric_algorithm"] }, { "required": ["header_key_id"] } ] } }, { "required": ["secret", "symmetric_algorithm", "header_key_id"], "not": { "anyOf": [ { "required": ["url"] }, { "required": ["algorithms"] }, { "required": ["refresh_interval"] }, { "required": ["refresh_unknown_kid"] } ] } } ] } }, "scope_claim": { "type": "string", "description": "The JWT claim to use when reading scopes for authorization. Only top level claims are supported. The default value is 'scope'.", "default": "scope", "minLength": 1 }, "header_name": { "type": "string", "description": "The name of the header. The header is used to extract the token from the request. The default value is 'Authorization'.", "default": "Authorization" }, "header_value_prefix": { "type": "string", "description": "The prefix of the header value. The prefix is used to extract the token from the header value. The default value is 'Bearer'.", "default": "Bearer" }, "header_sources": { "type": "array", "description": "Additional sources for the token. The sources are used to extract the token from the request.", "items": { "type": "object", "additionalProperties": false, "properties": { "type": { "type": "string", "description": "The type of the source. The only currently supported type is 'header'.", "enum": ["header"] }, "name": { "type": "string", "description": "The name of the header. The header is used to extract the token from the request.", "format": "http-header", "examples": ["X-Authorization"] }, "value_prefixes": { "type": "array", "description": "The prefixes of the header value. The prefixes are used to extract the token from the header value.", "items": { "type": "string" } } }, "required": ["type", "name"] } } } }, "ignore_introspection": { "type": "boolean", "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.", "default": false } } }, "authorization": { "type": "object", "additionalProperties": false, "properties": { "require_authentication": { "type": "boolean", "description": "Ensure that the request is authenticated. If the value is true, the request must be authenticated. If the value is false, the request does not need to be authenticated." }, "reject_operation_if_unauthorized": { "type": "boolean", "description": "Reject the operation if the request is not authorized. If the value is true, the operation is rejected if the request is not authorized." }, "enable_pre_fetch_field_authorization": { "type": "boolean", "description": "Authorize fields protected by an authorization rule in a single batch call before any subgraph fetch executes (scope-only, independent of the returned data), instead of filtering them out of the response after the fetch. This avoids fetching data that the client is not authorized to see." } } }, "rate_limit": { "type": "object", "description": "The configuration for the rate limit. The rate limit is used to limit the number of requests that can be made to the router.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean" }, "strategy": { "type": "string", "enum": ["simple"], "description": "The strategy used to enforce the rate limit. The supported strategies are 'simple'." }, "simple_strategy": { "type": "object", "additionalProperties": false, "properties": { "rate": { "type": "integer", "description": "The rate at which the requests are allowed. The rate is specified as a number of requests per second.", "minimum": 1 }, "burst": { "type": "integer", "description": "The maximum number of requests that are allowed to exceed the rate. The burst is specified as a number of requests.", "minimum": 1 }, "period": { "type": "string", "description": "The period of time over which the rate limit is enforced. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "duration": { "minimum": "1s" } }, "reject_exceeding_requests": { "type": "boolean", "description": "Reject the requests that exceed the rate limit. If the value is true, the requests that exceed the rate limit are rejected." }, "reject_status_code": { "type": "integer", "description": "The status code to return when the request is rejected. The default value is 200 (OK) as we're returning a well formed GraphQL response.", "default": 200 }, "hide_stats_from_response_extension": { "type": "boolean", "default": false, "description": "Hide the rate limit stats from the response extension. If the value is true, the rate limit stats are not included in the response extension." }, "overrides": { "type": "array", "description": "Per-key rate limit overrides. Each entry defines a regex pattern matched against the resolved rate-limit key. The first matching override wins; unmatched keys use the global defaults.", "items": { "type": "object", "additionalProperties": false, "properties": { "matching": { "type": "string", "description": "A regex pattern matched against the resolved rate-limit key." }, "rate": { "type": "integer", "description": "The override rate for matching keys.", "minimum": 1 }, "burst": { "type": "integer", "description": "The override burst for matching keys.", "minimum": 1 }, "period": { "type": "string", "description": "The override period for matching keys.", "duration": { "minimum": "1s" } } }, "required": ["matching", "rate", "burst", "period"] } } }, "required": ["rate", "burst", "period"] }, "storage": { "type": "object", "additionalProperties": false, "required": ["urls"], "properties": { "cluster_enabled": { "type": "boolean", "description": "Enable Redis Cluster connection, using the supplied URLs.", "default": false }, "urls": { "type": "array", "description": "The Redis connection URLs. The values are specified as a string with the format 'scheme://host:port', with optional auth and options added in to the URL. If cluster is enabled, will use them to instantiate a cluster connection.", "default": [], "items": { "type": "string" } }, "key_prefix": { "type": "string", "description": "The prefix of the keys used to store the rate limit data.", "default": "cosmo_rate_limit" } } }, "debug": { "type": "boolean", "description": "Enable the debug mode for the rate limit." }, "key_suffix_expression": { "type": "string", "description": "The expression to define a key suffix for the rate limit, e.g. by using request headers, claims, or a combination of both with a fallback strategy. The expression is specified as a string and needs to evaluate to a string. Please see https://expr-lang.org/ for more information." }, "error_extension_code": { "type": "object", "description": "If enabled, a code will be added to the extensions.code field of error objects related to rate limiting. This allows clients to easily identify if an error happened due to rate limiting.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "description": "Enable the error extension code for rate limiting." }, "code": { "type": "string", "description": "The error extension code for the rate limit.", "default": "RATE_LIMIT_EXCEEDED" } } } } }, "localhost_fallback_inside_docker": { "type": "boolean", "default": true, "description": "Enable the localhost fallback inside Docker. The localhost fallback is used to resolve the localhost address when running the router inside a Docker container. This should be only enabled for development and testing." }, "cdn": { "type": "object", "description": "The configuration for the CDN. The CDN is used to fetch the schema and configurations from the CDN.", "additionalProperties": false, "properties": { "url": { "type": "string", "format": "http-url", "description": "The URL of the CDN. The URL is used to register the router on the control-plane. The URL is specified as a string with the format 'scheme://host:port'." }, "cache_size": { "type": "string", "default": "100MB", "deprecated": true, "deprecationMessage": "The cache_size is deprecated. Please use the persisted_operations.cache instead.", "bytes": { "minimum": "10MB" }, "format": "bytes-string", "description": "The size of the cache used. The default value is 100MB." } } }, "mcp": { "type": "object", "description": "The configuration for the Model Context Protocol (MCP) server. MCP allows AI models to interact with your GraphQL APIs. By exposing individual GraphQL operations to the model, you can open your graph to empower AI agents working with your data. See https://cosmo-docs.wundergraph.com/router/mcp for more information.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the MCP server. If the value is true, the MCP server will be started." }, "server": { "type": "object", "description": "Server configuration for the MCP server.", "additionalProperties": false, "properties": { "listen_addr": { "type": "string", "description": "The address on which the MCP server listens for incoming requests. The address is specified as a string with the format 'host:port'.", "default": "localhost:5025", "format": "hostname-port" }, "base_url": { "type": "string", "description": "The base URL of the MCP server used for OAuth 2.0 discovery (RFC 9728). This URL is advertised in the Protected Resource Metadata endpoint and used to construct the resource metadata URL. Required when OAuth is enabled. The URL is specified as a string with the format 'scheme://host:port'.", "format": "http-url" }, "version": { "type": "string", "description": "The version reported to MCP clients as the server version in serverInfo, alongside the server name derived from graph_name. Use this to expose your own API version to AI agents. Defaults to the router release version when unset." }, "title": { "type": "string", "description": "A human-readable display name for this MCP server, reported to MCP clients in serverInfo. Clients show it in UIs, falling back to the machine name derived from graph_name when unset." }, "description": { "type": "string", "description": "A human-readable description of this MCP server, reported to MCP clients in serverInfo." }, "discover": { "type": "object", "description": "Configuration for the server identity exposed via the MCP server/discover method (protocol version 2026-07-28).", "additionalProperties": false, "properties": { "instructions": { "type": "string", "description": "Natural-language guidance for MCP clients (AI agents) on how to use this server effectively. Served in the server/discover response and in the legacy initialize response, so all clients receive it." } } } } }, "router_url": { "type": "string", "description": "Custom URL to use for the router GraphQL endpoint in MCP. Use this when your router is behind a proxy. This information is used in MCP responses to provide the real router URL to AI models.", "format": "url" }, "storage": { "type": "object", "description": "Storage provider configuration for the MCP server. This specifies where GraphQL operations are loaded from.", "additionalProperties": false, "properties": { "provider_id": { "type": "string", "description": "The ID of the storage provider to use for loading GraphQL operations. Only storage provider of type 'file_system' are supported. The provider must be configured in the storage_providers section." } }, "required": ["provider_id"] }, "session": { "type": "object", "description": "Session configuration for the MCP server. This controls how the MCP server handles client sessions.", "additionalProperties": false, "properties": { "stateless": { "type": "boolean", "default": true, "description": "Whether the MCP server should operate in stateless mode. When true, the server does not maintain session state between requests. When false, the server maintains session state, which can be useful for certain AI model integrations." } } }, "graph_name": { "type": "string", "default": "mygraph", "description": "The name of the graph to be used as suffix for the MCP server name. The default value is 'wundergraph-cosmo-mygraph'." }, "exclude_mutations": { "type": "boolean", "default": false, "description": "Exclude mutation operations from being exposed via MCP. This provides an additional security layer to prevent AI models from modifying data." }, "enable_arbitrary_operations": { "type": "boolean", "default": false, "description": "Enable arbitrary GraphQL operation execution through MCP. This allows AI models to execute any valid GraphQL query, mutation. Subscriptions are not supported yet. This is a powerful feature and should be used with caution." }, "expose_schema": { "type": "boolean", "default": false, "description": "Expose the full GraphQL schema through MCP. When enabled, AI models can request the complete schema of your API." }, "omit_tool_name_prefix": { "type": "boolean", "default": false, "description": "When enabled, MCP tool names generated from GraphQL operations omit the 'execute_operation_' prefix. For example, the GraphQL operation 'GetUser' results in a tool named 'get_user' instead of 'execute_operation_get_user'." }, "output_schema": { "type": "object", "description": "Configuration for MCP structured tool output (MCP specification revision 2025-06-18).", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "When enabled, every tool generated from a GraphQL operation declares an output schema derived from the operation's selection set, and successful tool results additionally carry the response as structured content. This lets MCP clients know the response shape ahead of time and validate results, at the cost of larger tools/list payloads and roughly doubled tool result sizes, which consume more of the AI model's context window." } } }, "resource_documentation": { "type": "string", "description": "A URL to a human-readable page describing this MCP resource, its access policies, and how to get started. Included in the RFC 9728 Protected Resource Metadata response if set.", "format": "http-url" }, "oauth": { "type": "object", "description": "OAuth/JWKS authentication configuration for the MCP server. When enabled, MCP tool calls require valid JWT authentication and the server implements OAuth 2.0 discovery mechanisms (RFC 8414, RFC 9728).", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable OAuth/JWKS authentication for the MCP server. When true, all MCP tool calls must include a valid JWT token." }, "authorization_server_url": { "type": "string", "description": "The base URL of the OAuth 2.0 authorization server. This URL is advertised to MCP clients via the Protected Resource Metadata endpoint (RFC 9728) to enable automatic discovery of OAuth endpoints. Clients will append '/.well-known/oauth-authorization-server' to this URL to discover token, authorization, and registration endpoints. Example: 'https://auth.example.com'", "format": "http-url", "deprecated": true, "deprecationMessage": "The authorization_server_url is deprecated. Please use the authorization_server_urls configuration instead." }, "authorization_server_urls": { "type": "array", "description": "A list of base URLs of OAuth 2.0 authorization servers. All URLs are advertised to MCP clients via the Protected Resource Metadata endpoint (RFC 9728). Use this field to trust more than one authorization server. Entries are merged with 'authorization_server_url' and duplicates are removed. Configure a JWKS entry for each issuer under 'jwks' so the router can validate its tokens.", "items": { "type": "string", "format": "http-url" } }, "scopes": { "type": "object", "description": "Configures which OAuth scopes are required for different MCP operations. All configured scopes are automatically unioned into 'scopes_supported' for OAuth metadata discovery.", "additionalProperties": false, "properties": { "initialize": { "type": "array", "description": "Scopes required for ALL HTTP requests (checked before JSON-RPC parsing). This is the baseline scope needed to establish an MCP connection.", "items": { "type": "string" } }, "tools_list": { "type": "array", "description": "Scopes required for the tools/list MCP method.", "items": { "type": "string" } }, "tools_call": { "type": "array", "description": "Scopes required for the tools/call MCP method (any tool).", "items": { "type": "string" } }, "execute_graphql": { "type": "array", "description": "Scopes required to call the execute_graphql built-in tool. Additive to tools_call scopes. Only relevant when enable_arbitrary_operations is true.", "items": { "type": "string" } }, "get_operation_info": { "type": "array", "description": "Scopes required to call the get_operation_info built-in tool. Additive to tools_call scopes.", "items": { "type": "string" } }, "get_schema": { "type": "array", "description": "Scopes required to call the get_schema built-in tool. Additive to tools_call scopes. Only relevant when expose_schema is true.", "items": { "type": "string" } } } }, "scope_challenge_include_token_scopes": { "type": "boolean", "default": false, "description": "When true, includes the token's existing scopes in the scope parameter of 403 insufficient_scope responses (workaround for MCP client SDKs that replace rather than accumulate scopes). When false (default), only the scopes required for the operation are returned (RFC 6750 strict)." }, "jwks": { "type": "array", "description": "List of JWKS (JSON Web Key Set) configurations for JWT token verification. Multiple JWKS providers can be configured for different authentication sources.", "items": { "type": "object", "additionalProperties": false, "properties": { "url": { "type": "string", "description": "The URL of the JWKs. The JWKs are used to verify the JWT (JSON Web Token). The URL is specified as a string with the format 'scheme://host:port'.", "format": "http-url" }, "audiences": { "type": "array", "description": "The audiences of the JWKs. The audiences are used to verify the JWT (JSON Web Token). The audiences are specified as a list of strings.", "items": { "type": "string" } }, "secret": { "type": "string", "description": "The secret of the JWKs" }, "symmetric_algorithm": { "type": "string", "description": "The symmetric algorithm used", "enum": ["HS256", "HS384", "HS512"] }, "header_key_id": { "type": "string", "description": "The KID header of the JWK token created using the secret" }, "allowed_use": { "type": "array", "description": "The allowed value of the use parameter for the JWKs. If not specified, only keys with use set to 'sig' will be used. If your server provides no use, you can add an empty value to allow those keys.", "default": ["sig"], "items": { "type": "string", "enum": ["sig", "enc", ""] } }, "algorithms": { "type": "array", "description": "The allowed algorithms for the keys that are retrieved from the JWKs. An empty list means that all algorithms are allowed.", "items": { "type": "string", "enum": [ "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "EdDSA" ] } }, "refresh_interval": { "type": "string", "duration": { "minimum": "5s" }, "description": "The interval at which the JWKs are refreshed. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "1m" }, "refresh_unknown_kid": { "type": "object", "description": "Controls rate-limited refresh behavior when a JWT KID is unknown.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable refresh attempts on unknown KID.", "default": false }, "max_wait": { "type": "string", "description": "Maximum time to wait for a refresh permit before giving up.", "default": "2m", "duration": { "minimum": "0s" } }, "interval": { "type": "string", "description": "Token refill interval for the rate limiter.", "default": "30s", "duration": { "minimum": "1s" } }, "burst": { "type": "integer", "description": "Burst size for the rate limiter.", "default": 2, "minimum": 1 } } } }, "oneOf": [ { "required": ["url"], "not": { "anyOf": [ { "required": ["secret"] }, { "required": ["symmetric_algorithm"] }, { "required": ["header_key_id"] } ] } }, { "required": ["secret", "symmetric_algorithm", "header_key_id"], "not": { "anyOf": [ { "required": ["url"] }, { "required": ["algorithms"] }, { "required": ["refresh_interval"] }, { "required": ["refresh_unknown_kid"] } ] } } ] } } } } }, "if": { "properties": { "oauth": { "properties": { "enabled": { "const": true } }, "required": ["enabled"] } }, "required": ["oauth"] }, "then": { "properties": { "server": { "required": ["base_url"] }, "oauth": { "properties": { "jwks": { "minItems": 1 } }, "required": ["jwks"] } }, "required": ["server", "oauth"] } }, "connect_rpc": { "type": "object", "description": "The configuration for the ConnectRPC server. ConnectRPC allows gRPC, Connect, and gRPC-Web clients to interact with your GraphQL APIs through protocol transcoding. Proto files define RPC services that map to GraphQL operations.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the ConnectRPC server. If the value is true, the ConnectRPC server will be started." }, "server": { "type": "object", "description": "Server configuration for the ConnectRPC server.", "additionalProperties": false, "properties": { "listen_addr": { "type": "string", "description": "The address on which the ConnectRPC server listens for incoming requests. The address is specified as a string with the format 'host:port'.", "default": "localhost:5026", "format": "hostname-port" }, "base_url": { "type": "string", "description": "The base URL of the ConnectRPC server. This is used for service reflection and documentation. By default, the base URL is relative to the URL that the router is running on. The URL is specified as a string with the format 'scheme://host:port'.", "format": "http-url" } } }, "storage": { "type": "object", "description": "Storage provider configuration for the ConnectRPC server. This specifies where proto files and GraphQL operations for all services are loaded from.", "additionalProperties": false, "properties": { "provider_id": { "type": "string", "description": "The ID of the storage provider to use for loading proto files and GraphQL operations for all services. Only storage provider of type 'file_system' are supported. The provider must be configured in the storage_providers section. This provider points to the root services directory, and the router will recursively discover all proto files and their associated operations within that directory structure." } } }, "graphql_endpoint": { "type": "string", "description": "Custom URL to use for the router GraphQL endpoint in ConnectRPC. Use this when your router is behind a proxy. This URL is used to forward RPC requests as GraphQL operations.", "format": "uri", "pattern": "^https?://" } }, "if": { "properties": { "enabled": { "const": true } } }, "then": { "required": ["storage"], "properties": { "storage": { "required": ["provider_id"] } } } }, "demo_mode": { "type": "boolean", "description": "Launch the router in demo mode. If no execution config is found, the router will start with a demo execution config and deploy a demo federated graph that can be used for testing purposes.", "default": false }, "events": { "type": "object", "description": "The configuration for EDFS. See https://cosmo-docs.wundergraph.com/router/event-driven-federated-subscriptions-edfs for more information.", "additionalProperties": false, "properties": { "skip_unavailable_providers": { "type": "boolean", "default": false, "description": "Start the router even when an event provider referenced by the execution config is unavailable, instead of aborting startup. This covers both a provider that is not defined in this configuration and a provider that is defined but cannot be reached at startup (e.g. the broker is down). The router logs an error and starts anyway, leaving only the fields backed by that provider unavailable; requests to them return an error instead of crashing the router. Defaults to false, in which case an unavailable provider prevents the router from starting." }, "providers": { "type": "object", "description": "The provider configuration. The provider configuration is used to configure the event-driven federated subscriptions.", "additionalProperties": false, "properties": { "nats": { "type": "array", "description": "Configuration used by the EDFS provider to connect to the NATS server.", "items": { "type": "object", "required": ["id", "url"], "additionalProperties": false, "properties": { "id": { "type": "string", "description": "The provider ID. The provider ID is used to identify the provider in the configuration." }, "url": { "type": "string", "description": "The provider URL. The URL is used to connect to the provider.", "format": "url" }, "authentication": { "description": "Authentication configuration for the NATS provider.", "type": "object", "oneOf": [ { "type": "object", "required": ["token"], "additionalProperties": false, "properties": { "token": { "type": "string", "description": "The token for token-based authentication." } } }, { "type": "object", "additionalProperties": false, "properties": { "user_info": { "type": "object", "description": "Userinfo configuration for the NATS provider.", "additionalProperties": false, "required": ["username", "password"], "properties": { "username": { "type": "string", "description": "The username for username/password-based authentication." }, "password": { "type": "string", "description": "The password for username/password-based authentication." } } } } } ] }, "tls": { "type": "object", "description": "TLS configuration for the NATS provider.", "additionalProperties": false, "properties": { "insecure_skip_ca_verification": { "type": "boolean", "default": false, "description": "Skip server certificate verification. Not recommended for production use." }, "ca_file": { "type": "string", "description": "Path to a custom CA certificate file (PEM) used to verify the server certificate.", "format": "file-path" }, "cert_file": { "type": "string", "description": "Path to the client certificate file (PEM) for mTLS. If set 'key_file' has to be set as well.", "format": "file-path" }, "key_file": { "type": "string", "description": "Path to the client private key file (PEM) for mTLS. If set 'cert_file' has to be set as well.", "format": "file-path" } }, "dependencies": { "cert_file": ["key_file"], "key_file": ["cert_file"] } }, "experiment_delete_durable_consumers_on_shutdown": { "type": "boolean", "description": "When enabled, all durable JetStream consumers created by this provider are deleted when the router shuts down normally. Defaults to false. NOTE: This option is experimental and may change in future versions.", "default": false } } } }, "kafka": { "type": "array", "description": "Configuration used by the EDFS provider to connect to the Kafka server.", "items": { "type": "object", "additionalProperties": false, "required": ["id", "brokers"], "properties": { "id": { "type": "string", "description": "The provider ID. The provider ID is used to identify the provider in the configuration." }, "brokers": { "type": "array", "description": "The list of Kafka brokers. The brokers are used to connect to the Kafka provider.", "items": { "type": "string", "format": "hostname-port" } }, "tls": { "type": "object", "description": "TLS configuration for the Kafka provider. If enabled, it uses SystemCertPool for RootCAs by default.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enables the TLS." } } }, "authentication": { "type": "object", "description": "SASL Authentication configuration for the Kafka provider.", "oneOf": [ { "type": "object", "additionalProperties": false, "required": ["sasl_plain"], "properties": { "sasl_plain": { "type": "object", "description": "Plain SASL Authentication configuration for the Kafka provider.", "additionalProperties": false, "required": ["username", "password"], "properties": { "username": { "type": "string", "description": "The username for plain SASL authentication." }, "password": { "type": "string", "description": "The password for plain SASL authentication." } } } } }, { "type": "object", "additionalProperties": false, "required": ["sasl_scram"], "properties": { "sasl_scram": { "type": "object", "description": "SCRAM SASL Authentication configuration for the Kafka provider.", "additionalProperties": false, "required": ["username", "password", "mechanism"], "properties": { "username": { "type": "string", "description": "The username for SCRAM SASL authentication." }, "password": { "type": "string", "description": "The password for SCRAM SASL authentication." }, "mechanism": { "type": "string", "description": "The mechanism for SCRAM SASL authentication.", "enum": ["SCRAM-SHA-256", "SCRAM-SHA-512"] } } } } } ] }, "fetch_max_wait": { "type": "string", "description": "The maximum wait time for fetching messages from the Kafka broker. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'. Setting this to a higher value can help reduce the number of requests to the Kafka broker.", "format": "go-duration" } } } }, "redis": { "type": "array", "description": "Configuration used by the EDFS provider to connect to the Redis server.", "items": { "type": "object", "additionalProperties": false, "required": ["id", "urls"], "properties": { "id": { "type": "string", "description": "The provider ID. The provider ID is used to identify the provider in the configuration." }, "urls": { "type": "array", "description": "The list of Redis URLs. An example of URL is \"redis://username:password@localhost:6379/11\"", "minItems": 1, "items": { "type": "string" } }, "cluster_enabled": { "type": "boolean", "description": "If enabled, the Redis cluster client is used to connect to the server.", "default": false } } } } } }, "handlers": { "type": "object", "description": "Configuration for Cosmo Streams / EDFS custom modules", "additionalProperties": false, "properties": { "on_receive_events": { "type": "object", "description": "Configuration for the OnReceiveEvents hook that is called for each subscriber when events are received from a broker.", "additionalProperties": false, "properties": { "max_concurrent_handlers": { "type": "integer", "description": "The maximum number of concurrent event receive handlers. This controls the concurrency of the OnReceiveEvents custom modules.", "minimum": 1, "default": 100 }, "handler_timeout": { "type": "string", "description": "The amount of time that OnReceiveEvents handlers can run in total for a single batch of events. Specify as a duration string (e.g., '5s', '1m', '500ms').", "default": "5s" } } }, "before_events_dispatch": { "type": "object", "description": "Configuration for the BeforeEventsDispatch hook, that is called once per event batch, before delivering them to subscribers.", "additionalProperties": false, "properties": { "handler_timeout": { "type": "string", "description": "The amount of time that BeforeEventsDispatch handlers can run in total for a single batch of events. Specify as a duration string (e.g., '5s', '1m', '500ms').", "default": "5s" } } } } } } }, "cache_warmup": { "type": "object", "description": "Cache Warmup pre-warms all caches (e.g. normalization, validation, planning) before accepting traffic.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the cache warmup.", "default": false }, "source": { "type": "object", "description": "The source of the cache warmup items. Only one can be specified. If empty, the cache warmup source is the Cosmo CDN and it requires a graph to be set.", "additionalProperties": false, "properties": { "filesystem": { "type": "object", "description": "The filesystem source of the cache warmup items.", "additionalProperties": false, "properties": { "path": { "type": "string", "description": "The path to the directory containing the cache warmup items.", "format": "file-path" } } }, "cdn": { "type": "object", "description": "The CDN source of the cache warmup items.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable or disable the CDN source for cache warmup.", "default": true } } } }, "oneOf": [ { "required": ["filesystem"] }, { "required": ["cdn"] } ] }, "workers": { "type": "integer", "description": "The number of workers for the cache warmup to run in parallel. Higher numbers decrease the time to warm up the cache but increase the load on the system.", "default": 8 }, "items_per_second": { "type": "integer", "description": "The number of cache warmup items to process per second. Higher numbers decrease the time to warm up the cache but increase the load on the system.", "default": 50 }, "item_delay": { "type": "string", "description": "A fixed delay applied after each cache warmup item is processed, per worker. Use to further smooth load during warmup. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'. Defaults to 0s (no delay).", "default": "0s" }, "timeout": { "type": "string", "description": "The timeout for warming up the cache. This can be used to limit the amount of time cache warming will block deploying a new config. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "30s", "duration": { "minimum": "1s" } }, "in_memory_fallback": { "type": "boolean", "description": "Enable in-memory fallback. When enabled, the router will reuse the cached query plans in memory and use it to rewarm the cache on schema changes and hot config reloads. The default value is true.", "default": true } } }, "router_config_path": { "type": "string", "format": "file-path", "deprecated": true, "deprecationMessage": "The router_config_path is deprecated. Please use the execution_config.file instead.", "description": "The path of the router execution config file. This file contains the information how your graph is resolved and configured. The path is specified as a string with the format 'path/to/file'." }, "router_registration": { "type": "boolean", "default": true, "description": "Enable the router registration. The router registration is used to register the router on the control-plane. The default value is true. This should not be modified unless you know what you are doing." }, "override_routing_url": { "type": "object", "description": "The configuration for the override routing URL. The override routing URL is used to override the routing URL for subgraphs.", "deprecationMessage": "The override_routing_url is deprecated. Please use the overrides.subgraphs.routing_url instead.", "deprecated": true, "additionalProperties": false, "properties": { "subgraphs": { "type": "object", "description": "The configuration for the subgraphs. The subgraphs are used to override the routing URL for the subgraphs.", "additionalProperties": { "type": "string", "description": "The URL of the subgraph. The URL is used to override the routing URL for the subgraph.", "format": "http-url" } } } }, "overrides": { "type": "object", "description": "The configuration to override subgraph config. The config is used to override the config for subgraphs.", "additionalProperties": false, "properties": { "subgraphs": { "type": "object", "description": "The configuration for the subgraphs. The subgraphs are used to override the config for the subgraphs.", "additionalProperties": { "type": "object", "properties": { "routing_url": { "type": "string", "description": "The URL of the subgraph. The URL is used to override the routing URL for the subgraph.", "format": "http-url" }, "subscription_url": { "type": "string", "description": "The Subscription URL of the subgraph. The URL is used to override the subscription URL for the subgraph.", "format": "http-url" }, "subscription_protocol": { "type": "string", "description": "The Subscription protocol of the subgraph. The protocol is used to override the subscription protocol for the subgraph." }, "subscription_websocket_subprotocol": { "type": "string", "description": "The Websocket subprotocol of the subgraph. The protocol is used to override the Websocket subprotocol for the subgraph." } } } } } }, "security": { "type": "object", "description": "The configuration for the security. The security is used to configure the security settings for the router.", "additionalProperties": false, "properties": { "block_mutations": { "type": "object", "description": "The configuration for blocking mutations.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Block mutation Operations. If the value is true, all operations are blocked. You can also specify a condition that is evaluated to determine if the mutation should be blocked." }, "condition": { "type": "string", "description": "The expression to evaluate if the mutation should be blocked. The expression is specified as a string and needs to evaluate to a boolean. Please see https://expr-lang.org/ for more information." } } }, "block_subscriptions": { "type": "object", "description": "The configuration for blocking subscriptions.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Block subscription Operations. If the value is true, all operations are blocked. You can also specify a condition that is evaluated to determine if the subscription should be blocked." }, "condition": { "type": "string", "description": "The expression to evaluate if the subscription should be blocked. The expression is specified as a string and needs to evaluate to a boolean. Please see https://expr-lang.org/ for more information." } } }, "block_non_persisted_operations": { "type": "object", "description": "The configuration for blocking non-persisted operations.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Block non-persisted operations (sent without operation hash). You can also specify a condition that is evaluated to determine if the non-persisted operation should be blocked." }, "condition": { "type": "string", "description": "The expression to evaluate if the non-persisted operation should be blocked. The expression is specified as a string and needs to evaluate to a boolean. Please see https://expr-lang.org/ for more information." } } }, "block_persisted_operations": { "type": "object", "description": "The configuration for blocking persisted operations.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Block persisted operations (sent with operation hash). You can also specify a condition that is evaluated to determine if the persisted operation should be blocked." }, "condition": { "type": "string", "description": "The expression to evaluate if the persisted operation should be blocked. The expression is specified as a string and needs to evaluate to a boolean. Please see https://expr-lang.org/ for more information." } } }, "complexity_calculation_cache": { "type": "object", "description": "The configuration for the complexity calculation cache. The complexity calculation cache is used to cache the complexity calculation for the queries.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "description": "Enable the complexity calculation cache. If the value is true, the complexity calculation cache is enabled." }, "size": { "type": "integer", "default": 1024, "description": "The size of the cache for the complexity calculation." } } }, "complexity_limits": { "type": "object", "description": "The configuration for complexity limits for queries", "additionalProperties": false, "properties": { "mode": { "type": "string", "enum": ["measure", "enforce"], "default": "enforce", "description": "Controls complexity limits behavior: 'measure' calculates complexity without rejecting operations; 'enforce' rejects operations exceeding limits." }, "depth": { "type": "object", "description": "The configuration for adding a max depth limit for query (how many nested levels you can have in a query). This limit prevents infinite querying, and also limits the size of the data returned. If the limit is 0, this limit isn't applied.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable query depth limits. If the value is true (default: false), and a valid limit value is set, a query depth will be calculated for your requests, and a limit applied to the queries." }, "limit": { "type": "integer", "description": "The depth limit for query. If the limit is 0, this limit isn't applied.", "default": 0, "minimum": 0 }, "ignore_persisted_operations": { "type": "boolean", "description": "Disable the max query depth limit for persisted operations. Since persisted operations are stored intentionally, users may want to disable the limit to consciously allow nested persisted operations.", "default": false } } }, "total_fields": { "type": "object", "description": "How many total fields are allowed to be in a particular query. This limit prevents queries from becoming too large.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the total field limit." }, "limit": { "type": "integer", "description": "The field limit for query. If the limit is 0, this limit isn't applied.", "default": 0, "minimum": 0 }, "ignore_persisted_operations": { "type": "boolean", "description": "Disable the total field limit for persisted operations. Since persisted operations are stored intentionally, users may want to disable the limit to consciously allow nested persisted operations.", "default": false } } }, "root_fields": { "type": "object", "description": "How many root fields are allowed in a query.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the root field query limit." }, "limit": { "type": "integer", "description": "The root field limit for query. If the limit is 0, this limit isn't applied.", "default": 0, "minimum": 0 }, "ignore_persisted_operations": { "type": "boolean", "description": "Disable the root fieldlimit for persisted operations. Since persisted operations are stored intentionally, users may want to disable the limit to consciously allow nested persisted operations.", "default": false } } }, "root_field_aliases": { "type": "object", "description": "How many root field aliases are allowed in a query.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the root field alias query limit." }, "limit": { "type": "integer", "description": "The root field alias limit for query. If the limit is 0, this limit isn't applied.", "default": 0, "minimum": 0 }, "ignore_persisted_operations": { "type": "boolean", "description": "Disable the root field alias limit for persisted operations. Since persisted operations are stored intentionally, users may want to disable the limit to consciously allow nested persisted operations.", "default": false } } }, "ignore_introspection": { "type": "boolean", "default": false, "description": "When set to true, complexity validation is ignored for all introspection queries." } } }, "cost_control": { "type": "object", "description": "Cost control based on @cost and @listSize directives.", "additionalProperties": false, "allOf": [ { "if": { "properties": { "enabled": { "const": true } }, "required": ["enabled"] }, "then": { "required": ["estimated_list_size"] } }, { "if": { "properties": { "mode": { "const": "enforce" } }, "required": ["mode"] }, "then": { "properties": { "max_estimated_limit": { "minimum": 1 } } } } ], "properties": { "enabled": { "type": "boolean", "default": false, "description": "When enabled, the router calculates costs for every operation." }, "mode": { "type": "string", "enum": ["measure", "enforce"], "default": "measure", "description": "Controls cost control behavior: 'measure' calculates costs without rejecting operations; 'enforce' rejects operations exceeding the estimated cost limit." }, "max_estimated_limit": { "type": "integer", "description": "Maximum allowed estimated cost for a query. Required to be positive when mode is 'enforce'.", "default": 0, "minimum": 0 }, "estimated_list_size": { "type": "integer", "description": "Default assumed size for list fields when no @listSize directive is specified. Required for estimated cost calculation.", "minimum": 1 }, "expose_headers": { "type": "boolean", "description": "Enable costs response headers for estimated and actuals operation costs." }, "ignore_implementing_type_weights": { "type": "boolean", "default": false, "description": "When enabled, ignores @cost weights from implementing types on abstract (interface/union) fields that have no weight of their own. Emulates Apollo's cost behavior." } } }, "operation_name_length_limit": { "type": "integer", "description": "The maximum allowed length of the operation name, 0 allows any length.", "default": "512", "minimum": 0 }, "depth_limit": { "type": "object", "description": "DEPRECATED (move to complexity_limits.depth): The configuration for adding a max depth limit for query (how many nested levels you can have in a query).", "deprecated": true, "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable query depth limits. If the value is true (default: false), and a valid limit value is set, a query depth will be calculated for your requests, and a limit applied to the queries." }, "limit": { "type": "integer", "description": "The depth limit for query. If the limit is 0, this limit isn't applied.", "default": 0, "minimum": 0 }, "cache_size": { "type": "integer", "default": 1024, "description": "The size of the cache for query depth. If users set a max_query_depth, we cache the decision per query." }, "ignore_persisted_operations": { "type": "boolean", "description": "Disable the max query depth limit for persisted operations. Since persisted operations are stored intentionally, users may want to disable the limit to consciously allow nested persisted operations.", "default": false } } }, "parser_limits": { "type": "object", "description": "The configuration to enforce parser limits for the query depth and fields count. This configuration leads to early fail for the queries above the limits during parsing. Do not change without need", "additionalProperties": false, "properties": { "approximate_depth_limit": { "type": "integer", "description": "The approximate cumulative depth limit of a query, including fragments. Set to 0 to disable.", "default": 200, "minimum": 0 }, "total_fields_limit": { "type": "integer", "description": "The total number of fields the parser will allow. Set to 0 to disable.", "default": 3500, "minimum": 0 } } } } }, "engine": { "type": "object", "description": "The configuration for the engine. The engine is used to execute the GraphQL queries, mutations and subscriptions. Only modify this if you know what you are doing.", "additionalProperties": false, "properties": { "validate_inline_arguments": { "type": "object", "description": "Detects, and optionally rejects, operations that carry hardcoded inline argument values instead of variables.", "additionalProperties": false, "properties": { "mode": { "type": "string", "enum": ["off", "permissive", "strict"], "default": "off", "description": "Controls the policy: 'off' disables it; 'permissive' detects and records inline arguments but still executes the operation; 'strict' rejects operations that use inline argument values." }, "enforce_http_status_code": { "type": "integer", "minimum": 100, "maximum": 599, "default": 400, "description": "HTTP status code returned when an operation is rejected in enforce mode." }, "error_code": { "type": "string", "default": "INLINE_ARGUMENT_VALUES_NOT_ALLOWED", "description": "The extensions.code emitted on rejection." }, "error_message": { "type": "string", "default": "Inline argument values are not allowed. Use variables instead.", "description": "The human-readable error/hint message surfaced to the client." }, "include_persisted_operations": { "type": "boolean", "default": false, "description": "When true, applies the policy to persisted operations as well. Persisted operations are exempt by default." }, "return_in_response_extensions": { "type": "boolean", "default": false, "description": "When true, reports detected inline arguments back to the client under extensions.inlineArguments of the GraphQL response. Applies only in non-enforcing mode." } } }, "debug": { "type": "object", "description": "The debug configuration. The debug configuration is used to enable the debug mode for the engine.", "additionalProperties": false, "properties": { "print_operation_transformations": { "type": "boolean", "description": "Print the operation transformations." }, "print_operation_enable_ast_refs": { "type": "boolean", "description": "Print the operation enable AST refs." }, "print_planning_paths": { "type": "boolean", "description": "Print the planning paths." }, "print_query_plans": { "type": "boolean", "description": "Print the query plans." }, "print_intermediate_query_plans": { "type": "boolean", "description": "Print intermediate query plans." }, "print_node_suggestions": { "type": "boolean", "description": "Print the node suggestions." }, "configuration_visitor": { "type": "boolean", "description": "Print the configuration visitor." }, "planning_visitor": { "type": "boolean", "description": "Print the planning visitor." }, "datasource_visitor": { "type": "boolean", "description": "Print the datasource visitor." }, "report_websocket_connections": { "type": "boolean", "description": "Print the websocket connections." }, "report_memory_usage": { "type": "boolean", "description": "Print the memory usage." }, "enable_resolver_debugging": { "type": "boolean", "description": "Enable verbose debug logging for the Resolver." }, "enable_persisted_operations_cache_response_header": { "type": "boolean", "description": "Enable the persisted operations cache response header. The persisted operations cache response header is used to cache the persisted operations in the client.", "deprecated": true, "deprecationMessage": "Deprecated. Use enable_cache_response_headers instead." }, "enable_normalization_cache_response_header": { "type": "boolean", "description": "Enable the normalization cache response header. The normalization cache response header is used to cache the normalized operations in the client.", "deprecated": true, "deprecationMessage": "Deprecated. Use enable_cache_response_headers instead." }, "enable_cache_response_headers": { "type": "boolean", "description": "Enable hit/miss response headers for the normalization cache, the persisted operations cache, and the execution plan cache." }, "always_include_query_plan": { "type": "boolean", "default": false, "description": "Always include the query plan in the response." }, "always_skip_loader": { "type": "boolean", "default": false, "description": "Always skip the loader. This will return no data but only render response extensions, e.g. to expose the query plan." }, "synchronous_cache_writes": { "type": "boolean", "default": false, "description": "Wait for the asynchronous operation-cache writes of a request to be applied before resolving the response, so that subsequent requests deterministically hit the caches. Intended for testing." } } }, "enable_single_flight": { "type": "boolean", "default": true, "description": "Enable the single flight. The single flight is used to deduplicate the requests to the same subgraphs." }, "force_enable_single_flight": { "type": "boolean", "default": false, "description": "Force enable single flight. Single flight is used to deduplicate identical in-flight subgraph requests. This flag always enables single flight, except for mutations. By default, SingleFlight / Request Deduplication is disabled when PreOriginHandlers are configured. This is because PreOriginHandlers can modify request headers, which has influence on the request deduplication key. If you're sure that your PreOriginHandlers won't interfere with the request deduplication key, you can enable it with this flag. For example, if you have a PreOriginHandler that only logs request headers, you can enable this flag to ensure that subgraph requests are still deduplicated." }, "enable_inbound_request_deduplication": { "type": "boolean", "default": true, "description": "Enable the inbound request deduplication. Inbound request deduplication hashes the normalized GraphQL operation, the variables, and the headers that will be forwarded to the subgraph to determine if the request is identical to an already in-flight request." }, "force_enable_inbound_request_deduplication": { "type": "boolean", "default": false, "description": "Force enable inbound request deduplication, even when PreOriginHandlers are configured." }, "enable_request_tracing": { "type": "boolean", "default": true, "description": "Capability gate for Advanced Request Tracing (ART). When false, ART is disabled regardless of headers, query parameters, or authentication." }, "force_unauthenticated_request_tracing": { "type": "boolean", "default": false, "description": "UNSAFE — DO NOT ENABLE IN PRODUCTION. Bypasses the authorization gate for Advanced Request Tracing (ART) when dev_mode is false. If false (default), ART request options require a valid WG request token. If true, ART request options are allowed without request-token authentication; this exposes internal subgraph URLs, request and response payloads, propagated headers (which may include auth tokens or API keys), and full query plans to any client that can reach the router. See https://cosmo-docs.wundergraph.com/router/advanced-request-tracing-art." }, "enable_execution_plan_cache_response_header": { "type": "boolean", "description": "Enable the execution plan cache response header. The execution plan cache response header is used to cache the execution plan in the client.", "deprecated": true, "deprecationMessage": "Deprecated. Use enable_cache_response_headers instead." }, "max_concurrent_resolvers": { "type": "integer", "description": "The maximum number of concurrent resolvers. The higher the number, the more requests can be processed in parallel but at the cost of more memory usage.", "default": 1024 }, "enable_net_poll": { "type": "boolean", "description": "Enables the more efficient poll implementation for all WebSocket implementations (client, server) of the router. This is only available on Linux and MacOS. On Windows or when the host system is limited, the default synchronous implementation is used.", "default": true }, "enable_multi_fetch": { "type": "boolean", "description": "Enables merging entity fetches to the same subgraph that execute in the same wave into a single batched request with aliased _entities fields. Merging reduces the number of subgraph requests.", "default": false }, "enable_schedule_fetches": { "type": "boolean", "description": "Enables the dependency-aware fetch scheduler, which organizes fetches into component-split, chain-inlined execution trees instead of the legacy wave-based structure.", "default": false }, "websocket_client_write_timeout": { "type": "string", "format": "go-duration", "default": "10s", "description": "The write timeout for WebSocket operations when the router connects to subgraphs (subscribe, unsubscribe, ping, pong). The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "websocket_server_read_timeout": { "type": "string", "format": "go-duration", "description": "The read timeout for the server-side WebSocket handler. The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "5s" }, "websocket_server_write_timeout": { "type": "string", "format": "go-duration", "description": "The write timeout for the server-side WebSocket handler. The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "10s" }, "websocket_server_poll_timeout": { "type": "string", "format": "go-duration", "description": "The poll timeout for the server-side WebSocket net poller. The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "1s" }, "websocket_server_conn_buffer_size": { "type": "integer", "default": 128, "description": "The buffer size for the server-side WebSocket net poller. Determines how many connections can be handled in one poll loop." }, "websocket_client_ping_interval": { "type": "string", "format": "go-duration", "description": "The Websocket client ping interval to the subgraph. Defines how often the router will ping the subgraph to signal that the connection is still alive. Timeout needs to be coordinated with the subgraph. The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "15s", "duration": { "minimum": "5s" } }, "websocket_client_ping_timeout": { "type": "string", "format": "go-duration", "description": "The Websocket client ping timeout to the subgraph. Defines how long the router will wait for a ping response from the subgraph. The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "30s", "duration": { "minimum": "5s" } }, "websocket_client_ack_timeout": { "type": "string", "format": "go-duration", "description": "The maximum time to wait for a connection_ack message after sending connection_init to a subgraph WebSocket. The timeout is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "30s", "duration": { "minimum": "1s" } }, "websocket_client_read_limit": { "type": "string", "format": "bytes-string", "description": "The maximum size of an incoming WebSocket message from a subgraph. The size is specified as a string with a number and a unit, e.g. 1KB, 1MB, 10MB. The supported units are 'KB', 'MB', 'GB'.", "default": "1MB", "bytes": { "minimum": "1KB" } }, "execution_plan_cache_size": { "type": "integer", "default": 1024, "description": "The size of the execution plan cache." }, "slow_plan_cache_size": { "type": "integer", "minimum": 1, "default": 300, "description": "The maximum number of entries in the slow plan cache." }, "slow_plan_cache_threshold": { "type": "string", "format": "go-duration", "description": "The minimum planning duration for a query plan to be stored in the slow plan cache.", "default": "100ms", "duration": { "minimum": "0ns" } }, "operation_hash_cache_size": { "type": "integer", "default": 2048, "description": "The size of the Operation Hash Cache. This should be larger than the plan cache because the hash is computed on the original query." }, "minify_subgraph_operations": { "type": "boolean", "default": true, "description": "Minify the subgraph operations. If the value is true, GraphQL Operations get minified after planning. This reduces the amount of GraphQL AST nodes the Subgraph has to parse, which ultimately saves CPU time and memory, resulting in faster response times." }, "enable_persisted_operations_cache": { "type": "boolean", "default": true, "description": "Enable the persisted operations cache. The persisted operations cache is used to cache normalized persisted operations to improve performance." }, "enable_normalization_cache": { "type": "boolean", "default": true, "description": "Enable the normalization cache. The normalization cache is used to cache normalized operations to improve performance." }, "normalization_cache_size": { "type": "integer", "default": 1024, "description": "The size of the normalization cache." }, "parsekit_pool_size": { "type": "integer", "default": 8, "description": "The size of the ParseKit pool. The ParseKit pool provides re-usable Resources for parsing, normalizing, validating and planning GraphQL Operations. Setting the pool size to a value much higher than the number of CPU Threads available will not improve performance, but only increase memory usage." }, "resolver_max_recyclable_parser_size": { "type": "integer", "default": 32768, "description": "Limits the size of the Parser that can be recycled back into the Pool. If set to 0, no limit is applied. This helps keep the Heap size more maintainable if you regularly perform large queries." }, "enable_validation_cache": { "type": "boolean", "default": true, "description": "Enable the validation cache. The validation cache is used to cache results of validating GraphQL Operations." }, "validation_cache_size": { "type": "integer", "default": 1024, "description": "The size of the validation cache." }, "disable_exposing_variables_content_on_validation_error": { "type": "boolean", "default": false, "description": "Disables exposing the variables content in the error response. This is useful to avoid leaking sensitive information in the error response." }, "enable_subgraph_fetch_operation_name": { "type": "boolean", "default": false, "description": "Enable appending the operation name to subgraph fetches. This will ensure that the operation name will be included in the corresponding subgraph requests using the following format: $OperationName__$SubgraphName__$FetchID." }, "disable_variables_remapping": { "type": "boolean", "default": false, "description": "Disables variables renaming during normalization. This option could have a negative impact on planner cache hits." }, "enable_require_fetch_reasons": { "type": "boolean", "default": false, "description": "Enables sending the \"fetch_reasons\" extension to upstream subgraphs (only) that explains why each field (marked with @openfed__requireFetchReasons) was requested. This flag does not expose the data to clients." }, "subscription_fetch_timeout": { "type": "string", "format": "go-duration", "default": "30s", "description": "The maximum time a subscription fetch can take before it is considered timed out. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "enable_defer": { "type": "boolean", "default": false, "description": "Enables support for the @defer directive, allowing clients to defer parts of a query so that the initial response is returned faster and deferred fields are streamed incrementally." }, "validate_required_external_fields": { "type": "boolean", "default": false, "description": "Enables validation of resolved input field set specified as an argument for \"requires\" directive. If this field set 'points' to a nullable fields marked as external, and if router resolves such a field set with null values with errors pointing to those values, then it will not provide such entities to the resolver of the field on which directive was specified." }, "relax_subgraph_operation_field_selection_merging_nullability": { "type": "boolean", "default": false, "description": "Relaxes nullability validation for field selection merging when enclosing types are non-overlapping concrete object types. When enabled, fields with differing nullability (e.g. String! vs String) in inline fragments on different union member types will not cause validation errors." }, "allow_string_literals_for_enums": { "type": "boolean", "default": false, "description": "Enables a deliberate deviation from the GraphQL specification that accepts a string literal where an enum value is expected, as long as the string content matches one of the enum's values (e.g. f(arg: \"VALUE1\") for enum SomeEnum { VALUE1 }). When disabled, only enum literals are valid inline values for enum types." } } }, "subgraph_error_propagation": { "type": "object", "description": "The configuration for the subgraph error propagation. The subgraph error propagation is used to propagate the errors from the subgraphs to the client.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": true, "deprecated": true, "deprecationMessage": "Enabled is deprecated. It was only relevant for 'wrapped' mode. Please remove it from your configuration. Subgraph errors will always be propagated to the client but only the message and code extension field. This can be customized with the other fields in this configuration.", "description": "Enable error propagation. If the value is true (default: false), Subgraph errors will be propagated to the client." }, "mode": { "type": "string", "enum": ["wrapped", "pass-through"], "default": "wrapped", "description": "The mode of error propagation. The supported modes are 'wrapped' (default) and 'pass-through'. The 'wrapped' mode wraps the error in a custom error object to hide internals. The 'pass-through' mode returns the error as is from the Subgraph." }, "rewrite_paths": { "type": "boolean", "default": true, "description": "Rewrite the paths of the Subgraph errors. If the value is true (default), the paths of the Subgraph errors will be rewritten to match the Schema of the Federated Graph." }, "attach_service_name": { "type": "boolean", "default": true, "description": "Attach the service name to each Subgraph error. If the value is true (default), the service name will be attached to the Subgraph errors." }, "default_extension_code": { "type": "string", "default": "DOWNSTREAM_SERVICE_ERROR", "description": "The default extension code. The default extension code is used to specify the default code for the Subgraph errors when the code is not present." }, "allowed_extension_fields": { "type": "array", "items": { "type": "string" }, "default": ["code"], "description": "The allowed extension fields. The allowed extension fields are used to specify which fields of the Subgraph errors are allowed to be propagated to the client." }, "allow_all_extension_fields": { "type": "boolean", "default": false, "description": "Allow all extension fields from Subgraph errors to be propagated to the client. If the value is true (default: false), all extension fields from Subgraph errors will be propagated, overriding the allowed_extension_fields configuration." }, "omit_locations": { "type": "boolean", "default": true, "description": "Omit the location field of Subgraph errors. If the value is true (default), the location field of Subgraph errors will be omitted. This is useful because the locations of a Subgraph error is internal to the Subgraph and not relevant to the client." }, "omit_extensions": { "type": "boolean", "default": false, "description": "Omit the extensions field of Subgraph errors. If the value is true (default: false), the extensions field of Subgraph errors will be omitted. This is useful in case you want to avoid leaking internal information to the client. Some users of GraphQL leverage the errors.extensions.code field to implement error handling logic in the client, in which case you might want to set this to false." }, "allowed_fields": { "type": "array", "items": { "type": "string" }, "default": [], "description": "The allowed fields in passthrough mode. It is used to control which fields of the Subgraph errors are allowed to be propagated to the client. If left empty only message is propagated. If left empty and omit_extensions or omit_locations are set to false, they will automatically be included." }, "propagate_status_codes": { "type": "boolean", "default": false, "description": "Propagate Subgraph HTTP status codes. If the value is true (default: false), Subgraph HTTP response status codes will be propagated to the client in the extensions statusCode field." } } }, "subgraph_extension_propagation": { "type": "object", "description": "Configuration for forwarding the response 'extensions' object from subgraphs to the client. Allows controlling which extension fields are propagated and how conflicts between subgraphs are resolved.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable forwarding of subgraph response extensions to the client." }, "allowed_extension_fields": { "type": "array", "items": { "type": "string" }, "description": "The extension fields that are allowed to be propagated from subgraphs to the client. If left empty, all extension fields will be forwarded." }, "algorithm": { "type": "string", "enum": ["first_write", "last_write"], "default": "first_write", "description": "The conflict resolution algorithm when multiple subgraphs return the same extension field. 'first_write' propagates the first response that wrote the field; 'last_write' propagates the last." } } }, "apollo_compatibility_flags": { "type": "object", "description": "To enable full compatibility with Apollo Federation, Apollo Gateway and Apollo Router, you can enable certain compatibility flags, allowing you to use Cosmo Router as a drop-in replacement for Apollo.", "additionalProperties": false, "properties": { "enable_all": { "type": "boolean", "default": false, "description": "Enable all Apollo compatibility flags. If the value is true, all Apollo compatibility flags are enabled." }, "value_completion": { "type": "object", "description": "Invalid __typename values will be returned in extensions.valueCompletion instead of errors.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "truncate_floats": { "type": "object", "description": "Truncate floats like 1.0 to 1, 2.0 to 2, etc.. Values like 1.1 or 2.2 will not be truncated.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "suppress_fetch_errors": { "type": "object", "description": "Suppresses fetch errors. When enabled, only the 'data' object is returned, suppressing errors. If disabled, fetch errors are included in the 'errors' array.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "replace_undefined_op_field_errors": { "type": "object", "description": "Produces the same error (message, extension code, status code) as Apollo when an invalid operation field is included in an operation selection set.", "deprecated": true, "deprecationMessage": "This property is deprecated. Please use 'use_graphql_validation_failed_status' instead.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "replace_invalid_var_errors": { "type": "object", "description": "Produces the same error (message, extension code but not status code) as Apollo when an invalid variable is supplied.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "replace_validation_error_status": { "type": "object", "description": "Produces the same error status code (400) as Apollo when validation fails.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "subscription_multipart_print_boundary": { "type": "object", "description": "Prints the multipart boundary right after the message in multipart subscriptions. Without this flag, the Apollo client wouldn't parse a message until the next one is pushed.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "use_graphql_validation_failed_status": { "type": "object", "description": "Uses Apollo compliant validation errors, including 400 status and GRAPHQL_VALIDATION_FAILED extension.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } } } }, "plugins": { "type": "object", "description": "The configuration for the router gRPC plugins.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable the router gRPC plugins." }, "path": { "type": "string", "description": "The path to the plugins directory. The plugins directory is used to load the plugins.", "default": "plugins" }, "registry": { "type": "object", "description": "Configuration for the plugin registry.", "additionalProperties": false, "properties": { "url": { "type": "string", "default": "cosmo-registry.wundergraph.com", "description": "The URL of the plugin registry." }, "insecure": { "type": "boolean", "default": false, "description": "If true, the plugin registry is accessed over plaintext HTTP without authentication. Intended for local development against an unauthenticated registry; never enable in production." } } } } }, "apollo_router_compatibility_flags": { "type": "object", "description": "To enable full compatibility with Apollo Router you can enable certain compatibility flags, allowing you to use Cosmo Router as a drop-in replacement for Apollo Router", "additionalProperties": false, "properties": { "replace_invalid_var_errors": { "type": "object", "description": "Produces the same error (message, extension code but not status code) as Apollo Router when an invalid variable is supplied.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "subrequest_http_error": { "type": "object", "description": "Prepends an additional error when subgraph HTTP response code is non-2XX, similar to Apollo Router.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } }, "skip_null_variables_error": { "type": "object", "description": "Skips the error when a null variable is supplied, similar to Apollo Router.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false } } } } }, "client_header": { "type": "object", "description": "The configuration to set custom client name and version header.", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The custom client name header." }, "version": { "type": "string", "description": "The custom client version header." } } }, "watch_config": { "type": "object", "description": "Configuration for watching changes to the router configuration.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable watching for configuration changes." }, "interval": { "type": "string", "description": "The interval at which the config file is checked for changes. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "10s", "duration": { "minimum": "5s" } }, "startup_delay": { "type": "object", "description": "Configuration for delaying the initial file watcher start to prevent synchronized reloads across multiple routers. If enabled, a random delay lasting between 0 and `maximum` will be added before the file watcher polling begins.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "default": false, "description": "Enable startup delay for the configuration watcher" }, "maximum": { "type": "string", "description": "The maximum time to wait before starting the config file watcher. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "10s", "duration": { "minimum": "5s" } } } } } } }, "$defs": { "jwks_configuration": { "type": "object", "additionalProperties": false, "properties": { "url": { "type": "string", "description": "The URL of the JWKs. The JWKs are used to verify the JWT (JSON Web Token). The URL is specified as a string with the format 'scheme://host:port'.", "format": "http-url" }, "audiences": { "type": "array", "description": "The audiences of the JWKs. The audiences are used to verify the JWT (JSON Web Token). The audiences are specified as a list of strings.", "items": { "type": "string" } }, "secret": { "type": "string", "description": "The secret of the JWKs" }, "symmetric_algorithm": { "type": "string", "description": "The symmetric algorithm used", "enum": ["HS256", "HS384", "HS512"] }, "header_key_id": { "type": "string", "description": "The KID header of the JWK token created using the secret" }, "algorithms": { "type": "array", "description": "The allowed algorithms for the keys that are retrieved from the JWKs. An empty list means that all algorithms are allowed.", "items": { "type": "string", "enum": [ "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "EdDSA" ] } }, "refresh_interval": { "type": "string", "duration": { "minimum": "5s" }, "description": "The interval at which the JWKs are refreshed. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'.", "default": "1m" }, "refresh_unknown_kid": { "type": "object", "description": "Controls rate-limited refresh behavior when a JWT KID is unknown.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable refresh attempts on unknown KID.", "default": false }, "max_wait": { "type": "string", "description": "Maximum time to wait for a refresh permit before giving up.", "default": "2m", "duration": { "minimum": "0s" } }, "interval": { "type": "string", "description": "Token refill interval for the rate limiter.", "default": "30s", "duration": { "minimum": "1s" } }, "burst": { "type": "integer", "description": "Burst size for the rate limiter.", "default": 2, "minimum": 1 } } } }, "oneOf": [ { "required": ["url"], "not": { "anyOf": [ { "required": ["secret"] }, { "required": ["symmetric_algorithm"] }, { "required": ["header_key_id"] } ] } }, { "required": ["secret", "symmetric_algorithm", "header_key_id"], "not": { "anyOf": [ { "required": ["url"] }, { "required": ["algorithms"] }, { "required": ["refresh_interval"] }, { "required": ["refresh_unknown_kid"] } ] } } ] }, "traffic_shaping_subgraph_request_rule": { "type": "object", "additionalProperties": false, "description": "The configuration for all subgraphs. The configuration is used to configure the traffic shaping for all subgraphs.", "properties": { "request_timeout": { "type": "string", "duration": { "minimum": "1s" }, "description": "The request timeout. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "dial_timeout": { "type": "string", "format": "go-duration", "description": "The dial timeout. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "tls_handshake_timeout": { "type": "string", "format": "go-duration", "description": "The TLS handshake timeout. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "response_header_timeout": { "type": "string", "format": "go-duration", "description": "The response header timeout. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "expect_continue_timeout": { "type": "string", "format": "go-duration", "description": "The expect continue timeout. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "keep_alive_idle_timeout": { "type": "string", "format": "go-duration", "description": "The keep alive idle timeout. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "keep_alive_probe_interval": { "type": "string", "duration": { "minimum": "5s" }, "description": "The keep alive probe interval. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "max_idle_conns": { "type": "integer", "default": 1024, "description": "MaxIdleConns controls the maximum number of idle (keep-alive) connections across all hosts. Zero means no limit" }, "max_conns_per_host": { "type": "integer", "default": 100, "description": "MaxConnsPerHost limits the total number of connections per host, including connections in the dialing, active, and idle states. Zero means no limit." }, "max_idle_conns_per_host": { "type": "integer", "default": 20, "description": "MaxIdleConnsPerHost, if non-zero, controls the maximum idle (keep-alive) connections to keep per-host. Zero will default to 2" }, "circuit_breaker": { "type": "object", "description": "The Circuit Breaker configuration, it allows you to enable and configure circuit breakers for subgraphs.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the circuit breaker" }, "request_threshold": { "type": "integer", "description": "The min number of pre-requisite requests required to start checking if the circuit breaker's status should be changed", "minimum": 1, "maximum": 10000 }, "error_threshold_percentage": { "type": "integer", "description": "The error threshold percentage that needs to be met in the rolling window to trigger the circuit to an open state", "minimum": 1, "maximum": 100 }, "sleep_window": { "type": "string", "format": "go-duration", "description": "After the circuit breaker is open, how long the circuit breaker will reject requests before allowing to send a half open request", "duration": { "minimum": "250ms", "maximum": "2m" } }, "half_open_attempts": { "type": "integer", "description": "How many failed attempts are allowed to check if an open circuit can now make successful requests", "minimum": 1, "maximum": 100 }, "required_successful": { "type": "integer", "description": "How many successful requests are required for a half open circuit breaker to close it", "minimum": 1, "maximum": 100 }, "rolling_duration": { "type": "string", "format": "go-duration", "description": "The duration of which information on failed and successful requests are stored", "duration": { "minimum": "5s", "maximum": "120s" } }, "num_buckets": { "type": "integer", "description": "The number of buckets which store circuit requests information within a given rolling duration", "minimum": 1, "maximum": 120 }, "execution_timeout": { "type": "string", "format": "go-duration", "description": "The maximum time to wait for a circuit execution to complete before timing out", "duration": { "minimum": "1ms", "maximum": "300s" } }, "max_concurrent_requests": { "type": "integer", "description": "The maximum number of concurrent requests allowed through the circuit breaker", "minimum": -1, "maximum": 10000 } } }, "retry": { "type": "object", "description": "The retry configuration. The retry configuration is used to configure the retry behavior for the subgraphs requests. See https://cosmo-docs.wundergraph.com/router/traffic-shaping#automatic-retry for more information.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean" }, "algorithm": { "type": "string", "description": "The algorithm used to calculate the retry interval. The supported algorithms are 'backoff_jitter'.", "enum": ["backoff_jitter"] }, "max_attempts": { "type": "integer", "default": 5, "minimum": 1, "description": "The maximum number of attempts. The default value is 5." }, "interval": { "type": "string", "format": "go-duration", "default": "3s", "description": "The time duration between each retry attempt. Increase with every retry. The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "max_duration": { "type": "string", "format": "go-duration", "default": "10s", "description": "The maximum allowable duration between retries (random). The period is specified as a string with a number and a unit, e.g. 10ms, 1s, 1m, 1h. The supported units are 'ms', 's', 'm', 'h'." }, "expression": { "type": "string", "description": "The expression used to determine if a request should be retried. The expression can reference status codes, error messages, and helper functions like IsRetryableStatusCode(), IsConnectionError(), IsHttpReadTimeout(), IsTimeout() (includes HTTP read timeouts). See https://expr-lang.org/ for expression syntax. Note: Mutations are never retried regardless of this expression. EOF errors are always retried at the transport layer regardless of this expression.", "default": "IsRetryableStatusCode() || IsConnectionError() || IsTimeout()" } } } } }, "traffic_shaping_header_rule": { "type": "object", "description": "The configuration for all subgraphs. The configuration is used to configure the traffic shaping for all subgraphs.", "additionalProperties": false, "properties": { "op": { "type": "string", "enum": ["propagate"], "examples": ["propagate"], "description": "The operation to perform on the header. The supported operations are 'propagate'. The 'propagate' operation is used to propagate the header to the subgraphs." }, "matching": { "type": "string", "examples": ["(?i)^X-Custom-.*"], "description": "The matching rule for the header. The matching rule is a regular expression that is used to match the header. Can't be used with 'named'." }, "negate_match": { "type": "boolean", "examples": ["true"], "description": "If set to true, the result of the 'matching' regex will be inverted. This is useful for simulating negative lookahead behavior, which is not natively supported." }, "named": { "type": "string", "examples": ["X-Test-Header"], "description": "The name of the header to match. Use the canonical version e.g. X-Test-Header. Can't be used with 'matching'." }, "rename": { "type": "string", "examples": ["X-Rename-Test-Header"], "description": "Rename is used to rename the named or the matching headers. It can be used with either the named or the matching." }, "default": { "type": "string", "examples": ["default-value"], "description": "The default value of the header in case it is not present in the request." } }, "dependentRequired": { "negate_match": ["matching"] }, "required": ["op"] }, "traffic_shaping_header_response_rule": { "type": "object", "description": "The configuration for all subgraphs. The configuration is used to configure the traffic shaping for all subgraphs.", "additionalProperties": false, "properties": { "op": { "type": "string", "enum": ["propagate"], "examples": ["propagate"], "description": "The operation to perform on the header. The supported operations are 'propagate'. The 'propagate' operation is used to propagate the header to the subgraphs." }, "matching": { "type": "string", "examples": ["(?i)^X-Custom-.*"], "description": "The matching rule for the header. The matching rule is a regular expression that is used to match the header. Can't be used with 'named'." }, "negate_match": { "type": "boolean", "examples": ["true"], "description": "If set to true, the result of the 'matching' regex will be inverted. This is useful for simulating negative lookahead behavior, which is not natively supported." }, "named": { "type": "string", "examples": ["X-Test-Header"], "description": "The name of the header to match. Use the canonical version e.g. X-Test-Header. Can't be used with 'matching'." }, "rename": { "type": "string", "examples": ["X-Rename-Test-Header"], "description": "Rename is used to rename the named or the matching headers. It can be used with either the named or the matching." }, "default": { "type": "string", "examples": ["default-value"], "description": "The default value of the header in case it is not present in the request." }, "algorithm": { "type": "string", "enum": ["first_write", "last_write", "append"], "examples": ["first_write"], "description": "The algorith, to use when multiple headers are present. The supported operations are '\"first_write\", \"last_write\", and \"append\". The 'first_write' retains the first value of a given header. The 'last_write' retains the last value of a given header. The 'append' appends all values of a given header." } }, "dependentRequired": { "negate_match": ["matching"] }, "required": ["op", "algorithm"] }, "router_response_header_rule": { "type": "object", "description": "The configuration for router response headers. This is used to set headers in response from the router to clients.", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The name of the header to set.", "examples": ["X-Custom-Header"] }, "expression": { "type": "string", "description": "The template expression to evaluate for the header value. The expression must return a string value." } }, "required": ["name", "expression"] }, "set_header_rule": { "type": "object", "description": "The configuration for setting headers. This is used to set specific headers in requests or responses.", "additionalProperties": false, "properties": { "op": { "type": "string", "const": "set", "description": "The 'set' operation is used to set a specific header value." }, "name": { "type": "string", "examples": ["X-API-Key"], "description": "The name of the header to set." }, "value": { "type": "string", "examples": ["My-Secret-Value"], "description": "The value to set for the header. This can include environment variables." }, "expression": { "type": "string", "description": "The template expression to evaluate. The expression must return a string value." }, "value_from": { "type": "object", "description": "DEPRECATED: Use expression instead. The configuration for the value from. The value from is used to extract a value from a request context and propagate it to subgraphs. This is currently only valid in requests", "additionalProperties": false, "required": ["context_field"], "properties": { "context_field": { "type": "string", "description": "The field name of the context from which to extract the value. The value is only extracted when a context is available otherwise the default value is used.", "enum": ["operation_name"] } } }, "from_file": { "type": "object", "description": "Source the header value from a file's contents. The file is loaded into memory and refreshed at refresh_interval, so request-time reads do not touch disk. Currently only valid in requests.", "additionalProperties": false, "required": ["path", "refresh_interval"], "properties": { "path": { "type": "string", "examples": ["/etc/secrets/api.key"], "description": "Absolute path to the file whose contents become the header value. Trailing whitespace is trimmed." }, "refresh_interval": { "type": "string", "format": "go-duration", "duration": { "minimum": "100ms" }, "default": "1m", "description": "Determines how often the file is checked for changes and re-read into memory. The minimum value is 100ms." } } } }, "required": ["op", "name"], "oneOf": [ { "required": ["value"] }, { "required": ["expression"] }, { "required": ["value_from"] }, { "required": ["from_file"] } ] }, "set_response_header_rule": { "type": "object", "description": "The configuration for setting response headers. This is used to set specific headers in responses. Unlike the request variant, 'from_file' is not allowed here.", "additionalProperties": false, "properties": { "op": { "type": "string", "const": "set", "description": "The 'set' operation is used to set a specific header value." }, "name": { "type": "string", "examples": ["X-Custom-Header"], "description": "The name of the header to set." }, "value": { "type": "string", "examples": ["My-Secret-Value"], "description": "The value to set for the header. This can include environment variables." }, "expression": { "type": "string", "description": "The template expression to evaluate. The expression must return a string value." }, "value_from": { "type": "object", "description": "DEPRECATED: Use expression instead. The configuration for the value from. The value from is used to extract a value from a request context and propagate it to subgraphs. This is currently only valid in requests", "additionalProperties": false, "required": ["context_field"], "properties": { "context_field": { "type": "string", "description": "The field name of the context from which to extract the value. The value is only extracted when a context is available otherwise the default value is used.", "enum": ["operation_name"] } } } }, "required": ["op", "name"], "oneOf": [ { "required": ["value"] }, { "required": ["expression"] }, { "required": ["value_from"] } ] }, "context_fields": { "type": "array", "description": "The fields to add to the logs. The fields are added to the logs as key-value pairs.", "items": { "type": "object", "description": "The configuration for custom fields. Custom attributes can be created from request headers or context fields. Not every context fields are available at all request life-cycle stages. If a value is a list, the value is JSON encoded for OTLP. For Prometheus, the values are exploded into multiple metrics with unique labels. Keep in mind, that every new custom attribute increases the cardinality.", "additionalProperties": false, "required": ["key"], "properties": { "key": { "type": "string", "description": "The key of the field." }, "default": { "type": "string", "description": "The default value of the field. If the value is not set, value_from is used. If both value and value_from are set, value_from has precedence and in case of a missing value_from, the default value is used." }, "value_from": { "type": "object", "description": "Defines a source for the field value e.g. from a request header. If both default and value_from are set, value_from has precedence.", "additionalProperties": false, "properties": { "request_header": { "type": "string", "description": "The name of the request header from which to extract the value. The value is only extracted when a request context is available otherwise the default value is used." }, "response_header": { "type": "string", "description": "The name of the response header from which to extract the value. The value is only extracted for subgraph access logs" }, "expression": { "type": "string", "description": "The expression used to evaluate to extract a value for logging. The expression is specified as a string. Please see https://expr-lang.org/ for more information on constructing expressions." }, "context_field": { "type": "string", "description": "The field name of the context from which to extract the value. The value is only extracted when a context is available otherwise the default value is used.", "enum": [ "operation_name", "operation_type", "operation_service_names", "operation_hash", "persisted_operation_sha256", "operation_sha256", "request_error", "response_error_message", "graphql_error_codes", "graphql_error_service_names", "operation_parsing_time", "operation_validation_time", "operation_planning_time", "operation_normalization_time" ] } } } } } } } }