# WunderGraph Cosmo Documentation WunderGraph Cosmo is a Full Lifecycle GraphQL API Management Solution designed to manage Federated Graphs at scale. It provides comprehensive tools for composing, routing, monitoring, and analyzing federated GraphQL architectures. The platform supports both Cosmo Cloud (managed service) and self-hosted deployments, with built-in support for GraphQL Federation v1 and v2, including real-time subscriptions. The Cosmo stack consists of four core components: the CLI (`wgc`) for platform management, the Control Plane for centralized orchestration, the Router for request routing and response aggregation, and the Studio web interface for visualization and collaboration. Together, these components enable teams to independently deploy and manage GraphQL subgraphs while maintaining a unified schema, with composition checks preventing breaking changes before they reach production. ## CLI Installation and Authentication The `wgc` CLI tool manages the Cosmo platform including schema operations, graph management, and user administration. ```bash # Install CLI globally npm install -g wgc@latest # Or run directly without installation npx wgc@latest # Login to Cosmo Cloud (opens browser for authentication) wgc auth login # Verify authentication and current organization wgc auth whoami # For CI/CD environments, use API key authentication export COSMO_API_KEY="your-api-key" export COSMO_API_URL="https://cosmo-cp.wundergraph.com" # default, optional ``` ## Namespace Management Namespaces provide environment isolation for graphs (e.g., development, staging, production). ```bash # Create a namespace for development environment wgc namespace create development # Create a production namespace wgc namespace create production # List all namespaces in the organization wgc namespace list # Rename a namespace wgc namespace rename development dev # Delete a namespace (removes all resources within it) wgc namespace delete -f development ``` ## Federated Graph Creation A federated graph represents your unified GraphQL schema composed of multiple subgraphs. ```bash # Create a federated graph with label matchers wgc federated-graph create production \ --namespace default \ --routing-url https://router.example.com/graphql \ --label-matcher team=backend department=engineering # Create with admission webhook for validation wgc federated-graph create staging \ --namespace staging \ --routing-url https://staging-router.example.com/graphql \ --label-matcher env=staging \ --admission-webhook-url https://admission.example.com \ --admission-webhook-secret "your-webhook-secret" # List all federated graphs wgc federated-graph list --namespace default # Update federated graph configuration wgc federated-graph update production \ --namespace default \ --routing-url https://new-router.example.com/graphql # Delete a federated graph wgc federated-graph delete production --namespace default ``` ## Subgraph Creation and Publishing Subgraphs are individual GraphQL services that compose into a federated graph. ```bash # Create a subgraph with labels for matching wgc subgraph create products \ --namespace default \ --label team=backend \ --routing-url http://products-service:4001/graphql # Create subgraph with custom subscription configuration wgc subgraph create notifications \ --namespace default \ --label team=backend \ --routing-url http://notifications-service:4002/graphql \ --subscription-url ws://notifications-service:4002/graphql \ --subscription-protocol ws \ --websocket-subprotocol graphql-ws # Create an Event-Driven Graph (for Kafka/NATS/Redis subscriptions) wgc subgraph create events \ --namespace default \ --label team=streaming \ --edg # Publish schema to existing subgraph wgc subgraph publish products \ --namespace default \ --schema ./schemas/products.graphql # Create and publish in one command wgc subgraph publish inventory \ --namespace default \ --schema ./schemas/inventory.graphql \ --routing-url http://inventory-service:4003/graphql \ --label team=backend # Fetch current subgraph schema wgc subgraph fetch products --namespace default > products.graphql # List all subgraphs wgc subgraph list --namespace default ``` ## Schema Checks Validate schema changes for breaking changes and composition errors before deployment. ```bash # Check schema changes against existing federated graphs wgc subgraph check products \ --namespace default \ --schema ./schemas/products-new.graphql # Check with JSON output for CI/CD automation wgc subgraph check products \ --namespace default \ --schema ./schemas/products-new.graphql \ --json # Write check results to file wgc subgraph check products \ --namespace default \ --schema ./schemas/products-new.graphql \ --out ./check-results.json # Check impact of deleting a subgraph wgc subgraph check products --namespace default --delete # Check new subgraph without creating it first wgc subgraph check new-service \ --namespace default \ --schema ./schemas/new-service.graphql \ --label team=backend # Skip traffic analysis (treat all breaking changes as errors) wgc subgraph check products \ --namespace default \ --schema ./schemas/products.graphql \ --skip-traffic-check # Set VCS context for better traceability export COSMO_VCS_AUTHOR="developer@example.com" export COSMO_VCS_COMMIT="abc123def456" export COSMO_VCS_BRANCH="feature/new-api" wgc subgraph check products --namespace default --schema ./schema.graphql ``` ## Router Token Management Router tokens authenticate the router with the control plane. ```bash # Create a router token for a federated graph wgc router token create production-router \ --graph-name production \ --namespace default # Output: # Successfully created token production-router for graph production # <- Store securely, shown only once # List existing router tokens wgc router token list --graph-name production --namespace default # Delete a router token wgc router token delete production-router \ --graph-name production \ --namespace default ``` ## Router Installation and Running The Cosmo Router handles GraphQL Federation request routing. ```bash # Run router with Docker (recommended for quick start) docker run \ --name cosmo-router \ --rm \ -p 3002:3002 \ --add-host=host.docker.internal:host-gateway \ --pull always \ -e DEV_MODE=true \ -e LISTEN_ADDR=0.0.0.0:3002 \ -e GRAPH_API_TOKEN="your-graph-api-token" \ ghcr.io/wundergraph/cosmo/router:latest # Run with custom configuration file docker run \ --name cosmo-router \ --rm \ -p 3002:3002 \ -v $(pwd)/config.yaml:/config.yaml \ -e CONFIG_PATH=/config.yaml \ -e GRAPH_API_TOKEN="your-graph-api-token" \ ghcr.io/wundergraph/cosmo/router:latest # Download binary directly (Linux AMD64 example) curl -L -o router https://github.com/wundergraph/cosmo/releases/latest/download/router-linux-amd64 chmod +x router export GRAPH_API_TOKEN="your-graph-api-token" ./router ``` ## Router Configuration Configure router behavior through YAML with environment variable expansion. ```yaml # config.yaml - Complete router configuration example # yaml-language-server: $schema=https://raw.githubusercontent.com/wundergraph/cosmo/main/router/pkg/config/config.schema.json version: "1" # Core settings listen_addr: "0.0.0.0:3002" log_level: "info" json_log: true dev_mode: false # Graph authentication graph: token: "${GRAPH_API_TOKEN}" # GraphQL settings playground_enabled: true playground_path: "/" introspection: enabled: true # Health checks health_check_path: "/health" readiness_check_path: "/health/ready" liveness_check_path: "/health/live" # Graceful shutdown shutdown_delay: 60s grace_period: 30s poll_interval: 10s # CORS configuration cors: enabled: true allow_origins: ["https://example.com", "https://*.example.com"] allow_methods: ["HEAD", "GET", "POST"] allow_headers: ["Origin", "Content-Length", "Content-Type", "Authorization"] allow_credentials: true max_age: 5m # Traffic shaping traffic_shaping: router: max_request_body_size: 5MB all: request_timeout: 60s dial_timeout: 30s retry: enabled: true algorithm: "backoff_jitter" max_attempts: 5 interval: 3s max_duration: 10s circuit_breaker: enabled: true request_threshold: 20 error_threshold_percentage: 50 sleep_window: 30s # Header propagation headers: all: request: - op: "propagate" named: "Authorization" - op: "propagate" matching: "(?i)^x-custom-.*" - op: "set" name: "X-Router-Version" value: "1.0.0" response: - op: "propagate" algorithm: "append" named: "X-Request-ID" ``` ## Authentication Configuration Configure JWT/JWKS authentication for incoming requests. ```yaml # config.yaml - Authentication section version: "1" authentication: jwt: jwks: # Multiple JWKS endpoints supported - url: "https://auth.example.com/.well-known/jwks.json" refresh_interval: 1m algorithms: ["RS256", "RS384", "RS512"] audiences: ["https://api.example.com"] refresh_unknown_kid: enabled: true max_wait: 2m interval: 30s burst: 2 # Second auth provider - url: "https://auth2.example.com/.well-known/jwks.json" refresh_interval: 2m algorithms: ["ES256", "EdDSA"] # Symmetric key authentication - symmetric_algorithm: HS256 secret: "${JWT_SECRET}" header_key_id: "symmetric-key-1" # Header configuration header_name: "Authorization" header_value_prefix: "Bearer" # Additional header sources header_sources: - type: header name: "X-Auth-Token" value_prefixes: ["Token", "Bearer"] authorization: require_authentication: true reject_operation_if_unauthorized: false # Optional: bypass auth for introspection # authentication: # ignore_introspection: true # Optional: dedicated introspection secret introspection: enabled: true secret: "${INTROSPECTION_SECRET}" ``` ## Telemetry and Monitoring Configure OpenTelemetry tracing and Prometheus metrics. ```yaml # config.yaml - Telemetry configuration version: "1" telemetry: service_name: "cosmo-router" resource_attributes: - key: "environment" value: "production" - key: "region" value: "us-east-1" # OpenTelemetry Tracing tracing: enabled: true sampling_rate: 0.1 # 10% sampling parent_based_sampler: true batch_timeout: 10s export_graphql_variables: false propagation: trace_context: true baggage: true jaeger: false b3: false datadog: false exporters: - exporter: http endpoint: "https://otel-collector.example.com:4318" headers: Authorization: "Bearer ${OTEL_TOKEN}" # OpenTelemetry Metrics metrics: otlp: enabled: true router_runtime: true graphql_cache: true exporters: - exporter: grpc endpoint: "otel-collector.example.com:4317" temporality: delta # Prometheus metrics endpoint prometheus: enabled: true path: "/metrics" listen_addr: "0.0.0.0:8088" exclude_metrics: [] exclude_metric_labels: [] # GraphQL metrics for Cosmo Studio graphql_metrics: enabled: true collector_endpoint: "https://cosmo-metrics.wundergraph.com" # Access logs access_logs: enabled: true level: info router: fields: - key: "operation_name" value_from: context_field: operation_name - key: "client_name" value_from: request_header: "GraphQL-Client-Name" ``` ## Event-Driven Subscriptions (EDFS) Configure event streaming with NATS, Kafka, or Redis. ```yaml # config.yaml - Event providers configuration version: "1" events: providers: nats: - id: default url: "nats://nats.example.com:4222" authentication: token: "${NATS_TOKEN}" # Or use user credentials: # user_info: # username: "${NATS_USER}" # password: "${NATS_PASSWORD}" kafka: - id: my-kafka brokers: - "kafka1.example.com:9092" - "kafka2.example.com:9092" tls: enabled: true authentication: sasl_plain: username: "${KAFKA_USER}" password: "${KAFKA_PASSWORD}" redis: - id: my-redis urls: - "redis://redis.example.com:6379" ``` ## Persisted Operations Configure persisted queries for security and performance. ```yaml # config.yaml - Persisted operations configuration version: "1" # Storage providers for operations storage_providers: s3: - id: "operations-bucket" endpoint: "s3.amazonaws.com" bucket: "my-persisted-operations" region: "us-east-1" access_key: "${AWS_ACCESS_KEY_ID}" secret_key: "${AWS_SECRET_ACCESS_KEY}" secure: true redis: - id: "apq-cache" urls: ["redis://redis.example.com:6379"] cluster_enabled: false # Persisted operations (pre-registered queries) persisted_operations: disabled: false log_unknown: true safelist: enabled: false # When true, only persisted operations allowed cache: size: 100MB storage: provider_id: "operations-bucket" object_prefix: "operations" # Automatic Persisted Queries (APQ) automatic_persisted_queries: enabled: true cache: size: 10MB ttl: 900 # seconds storage: provider_id: "apq-cache" object_prefix: "cosmo_apq" ``` ## Security Configuration Configure query complexity limits and security policies. ```yaml # config.yaml - Security configuration version: "1" security: # Block specific operation types block_mutations: enabled: false condition: "request.header.Get('x-read-only') == 'true'" block_subscriptions: enabled: false block_non_persisted_operations: enabled: false # Query complexity limits complexity_calculation_cache: enabled: true size: 1024 complexity_limits: depth: enabled: true limit: 10 ignore_persisted_operations: true total_fields: enabled: true limit: 100 ignore_persisted_operations: true root_fields: enabled: true limit: 5 ignore_persisted_operations: true # Parser limits parser_limits: approximate_depth_limit: 200 total_fields_limit: 3500 operation_name_length_limit: 512 # File upload settings file_upload: enabled: true max_file_size: 50MB max_files: 5 ``` ## Rate Limiting Configure Redis-backed rate limiting. ```yaml # config.yaml - Rate limiting configuration version: "1" rate_limit: enabled: true strategy: "simple" simple_strategy: rate: 100 # requests per period burst: 50 # max burst period: 1s # time window reject_exceeding_requests: false hide_stats_from_response_extension: false storage: urls: ["redis://redis.example.com:6379"] cluster_enabled: false key_prefix: "cosmo_rate_limit" # Dynamic rate limit key based on user key_suffix_expression: "request.auth.claims.sub ?? request.header.Get('X-Forwarded-For')" error_extension_code: enabled: true code: "RATE_LIMIT_EXCEEDED" ``` ## WebSocket Configuration Configure WebSocket subscriptions and protocols. ```yaml # config.yaml - WebSocket configuration version: "1" websocket: enabled: true # Absinthe protocol support for legacy clients absinthe_protocol: enabled: true handler_path: "/absinthe/socket" # Forward headers and params to subgraphs forward_upgrade_headers: enabled: true allow_list: ["Authorization", "X-Request-ID"] forward_upgrade_query_params: enabled: true allow_list: ["token"] forward_initial_payload: true # Extract client info from WebSocket payload client_info_from_initial_payload: enabled: true name_field: "graphql-client-name" version_field: "graphql-client-version" forward_to_request_headers: enabled: true name_target_header: "GraphQL-Client-Name" version_target_header: "GraphQL-Client-Version" # WebSocket authentication from payload authentication: from_initial_payload: enabled: true key: "authorization" export_token: enabled: true header_key: "Authorization" ``` ## Subgraph Error Propagation Configure how subgraph errors are exposed to clients. ```yaml # config.yaml - Error propagation configuration version: "1" subgraph_error_propagation: enabled: true mode: "wrapped" # "wrapped" or "pass-through" propagate_status_codes: false rewrite_paths: true omit_locations: true omit_extensions: false default_extension_code: "DOWNSTREAM_SERVICE_ERROR" attach_service_name: true allow_all_extension_fields: false allowed_extension_fields: ["code", "message"] ``` ## Local Development with Router Compose Generate router configuration locally for development. ```bash # Compose router config from local subgraph schemas wgc router compose \ --input ./subgraphs.yaml \ --output ./router-config.json # subgraphs.yaml example: # version: 1 # subgraphs: # - name: products # routing_url: http://localhost:4001/graphql # schema: # file: ./schemas/products.graphql # - name: users # routing_url: http://localhost:4002/graphql # schema: # file: ./schemas/users.graphql # Fetch router config from control plane wgc router fetch production --namespace default --out ./router-config.json # Run router with local config docker run \ --name cosmo-router \ --rm \ -p 3002:3002 \ -v $(pwd)/router-config.json:/config.json \ -e ROUTER_CONFIG_PATH=/config.json \ -e DEV_MODE=true \ ghcr.io/wundergraph/cosmo/router:latest ``` ## GraphQL Query Examples Execute GraphQL operations against the router. ```bash # Simple query curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -d '{"query": "{ employees { id name } }"}' # Query with variables curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -d '{ "query": "query GetEmployee($id: ID!) { employee(id: $id) { id name email } }", "variables": {"id": "123"} }' # Authenticated request curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \ -d '{"query": "{ me { id email } }"}' # Introspection query curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -d '{"query": "{ __schema { types { name } } }"}' # APQ - First request registers query curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -d '{ "query": "{ employees { id name } }", "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" } } }' # APQ - Subsequent requests use hash only curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -d '{ "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" } } }' ``` ## Complete Onboarding Workflow End-to-end example of setting up a federated graph. ```bash # 1. Install CLI and authenticate npm install -g wgc@latest wgc auth login wgc auth whoami # 2. Create namespace wgc namespace create development # 3. Create federated graph wgc federated-graph create my-api \ --namespace development \ --routing-url https://router.example.com/graphql # 4. Create and publish subgraphs wgc subgraph create products \ --namespace development \ --routing-url http://products:4001/graphql wgc subgraph publish products \ --namespace development \ --schema ./schemas/products.graphql wgc subgraph create users \ --namespace development \ --routing-url http://users:4002/graphql wgc subgraph publish users \ --namespace development \ --schema ./schemas/users.graphql # 5. Create router token wgc router token create dev-router \ --graph-name my-api \ --namespace development # Save the token output securely # 6. Run router export GRAPH_API_TOKEN="" docker run --name cosmo-router --rm -p 3002:3002 \ -e DEV_MODE=true \ -e LISTEN_ADDR=0.0.0.0:3002 \ -e GRAPH_API_TOKEN="$GRAPH_API_TOKEN" \ ghcr.io/wundergraph/cosmo/router:latest # 7. Test the endpoint curl -X POST http://localhost:3002/graphql \ -H "Content-Type: application/json" \ -d '{"query": "{ products { id name } users { id email } }"}' # 8. Check schema changes before deploying wgc subgraph check products \ --namespace development \ --schema ./schemas/products-v2.graphql # 9. Publish approved changes wgc subgraph publish products \ --namespace development \ --schema ./schemas/products-v2.graphql ``` ## Summary WunderGraph Cosmo provides a complete platform for managing federated GraphQL architectures at scale. The primary use cases include: building distributed GraphQL APIs with independent team ownership of subgraphs, implementing schema governance with composition checks and breaking change detection, monitoring API performance with built-in analytics and distributed tracing, and securing GraphQL endpoints with JWT authentication and rate limiting. Integration patterns center around the CLI-driven workflow for schema management, Docker-based router deployment for both development and production, and YAML configuration for customizing router behavior. Teams typically integrate Cosmo into CI/CD pipelines using `wgc subgraph check` for PR validation and `wgc subgraph publish` for automated deployments. The router supports multiple deployment targets including Kubernetes (via Helm charts), Docker Compose for development, and serverless platforms. Event-driven architectures can leverage NATS, Kafka, or Redis for real-time subscriptions across federated services.