Repository navigation
Immutable
release. Only release title and notes can be modified.
9.0.0 (2026-10-30)
Relay Proxy v9 adds support for the FDv2 data system, replaces OpenCensus with OpenTelemetry for metrics, tracing and logs, and ships only distroless Docker images. This entry covers every change since v8. Version 9.0.0 also includes every fix and feature released on v8 through 8.23.4.
⚠ BREAKING CHANGES
Metrics and observability
- OpenCensus has been replaced with OpenTelemetry, and the Datadog, Stackdriver and Prometheus exporters have been removed. The
[Datadog],[Stackdriver]and[Prometheus]config sections and theUSE_DATADOG,USE_STACKDRIVER,USE_PROMETHEUS,DATADOG_*,STACKDRIVER_*andPROMETHEUS_*variables are no longer supported. Enable OTLP export withUSE_OTLP([OpenTelemetry] enabled) and configure it with the standard OpenTelemetry environment variables (OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_EXPORTER_OTLP_HEADERS,OTEL_SERVICE_NAME,OTEL_RESOURCE_ATTRIBUTES, and so on). Prometheus and Datadog can receive metrics over OTLP; see docs/metrics.md. (#628, #639) - Metric names follow the OpenTelemetry semantic conventions.
connectionsis replaced byhttp.server.active_requests, which counts in-flight requests on every endpoint.newconnectionsis replaced by thelaunchdarkly.relay.requestscounter.requestsis replaced by thehttp.server.request.durationhistogram. Filter onlaunchdarkly.relay.endpoint.type="stream"to get the v8 stream connection numbers. (#635, #802, #810) - Metric attributes are renamed to the semantic conventions under a single
launchdarkly.*vendor namespace (for examplelaunchdarkly.environment.name,http.route,http.request.method,user_agent.original). The v8relayId,platformCategoryandsdkWrappertags are no longer reported. Use theservice.instance.idresource attribute to identify a Relay instance. (#809) - High-cardinality attributes are no longer recorded on the request metrics, and
http.request.methodis normalized. Client-supplied attributes are not recorded on unauthenticated requests. (#807, #907)
Logging
- Logging now uses Go's
log/slog, and log messages carry structured key-value fields. The output format has changed. Text lines look liketime=… level=INFO msg="…", and JSON output (LOG_FORMAT=json) uses thetimeandmsgkeys instead oftimestampandmessage. Update any log parsing that depends on the v8 format. (#643)
Configuration
- The
exitOnErrorandignoreConnectionErrorsoptions (EXIT_ON_ERROR,IGNORE_CONNECTION_ERRORS) are removed. Neither changed whether Relay kept running at startup; it keeps running and retrying, as it has since 6.0.0. WithexitAlways, Relay now waits for every environment and exits non-zero if any failed to initialize. Setting either option now fails configuration loading. (#954) - The
EVENTS_INLINE_USERSoption ([Events] inlineUsers) is removed. It has had no effect since context-aware event payloads. (#650) - The per-environment
projKeyoption (LD_PROJ_KEY_<env>) is removed. (#891) - Payload filters are no longer served, and the
[Filters "<project>"]configuration (LD_FILTER_KEYS_<project>) is removed. (#867)
HTTP and status resource
- Cacheable responses use the standard weak ETag form
W/"<value>"instead ofrelay-<value>. Clients and caches holding a v8 ETag will receive a full response on their next request. (#647) - The status resource reports each environment's full key set in new
sdkKeysandmobileKeysarrays, each entry carrying its own optional expiry. TheexpiringSdkKeyfield is removed.sdkKeyandmobileKeyremain. (#898)
Docker images and packaging
- Only distroless Docker images are published, built on
gcr.io/distroless/static-debian13and running as a nonroot user. The unsuffixed tags (latest,v9,9.x.y) point at the distroless image, anddistroless-prefixed aliases are also published. The Alpine images and-alpinetags are no longer published. The image has no shell or package manager, so derived images that run shell commands or expect root need to change. (#942, #951) - The i386 Docker image is no longer published. The
linux_386archive and the deb and rpm packages are still available. (#942) - The Go module path is now
github.com/launchdarkly/ld-relay/v9. (#632)
Features
FDv2 data system
- Relay serves the FDv2 streaming and polling endpoints used by server-side SDKs that support the new data system, and receives its own data from LaunchDarkly through the FDv2 data system. (#626, #627)
- Relay serves FDv2 streaming and polling for mobile and JavaScript client-side SDKs. (#629)
- Offline mode runs on the FDv2 data system. (#561)
OpenTelemetry
- Export metrics over OTLP via gRPC or HTTP to any compatible backend.
OTEL_EXPORTER_OTLP_PROTOCOLaccepts the values the OpenTelemetry specification defines. (#628, #950) - Distributed tracing, exported over OTLP alongside metrics, including spans for polling payload serialization and response writes. End-user contexts are redacted from the
url.pathspan attribute. (#644, #784, #791) - Log export over OTLP when
USE_OTLPis enabled. (#643) - Log, trace and metric export can each be turned off with
OTEL_LOGS_EXPORTER,OTEL_TRACES_EXPORTERandOTEL_METRICS_EXPORTER. (#887) - Event processing metrics: bytes received, events and bytes sent, delivery failures, drops and queue depth. (#631)
- The status resource is exported as OpenTelemetry metrics. Per-environment status metrics are available behind
OTEL_ENVIRONMENT_STATUS_METRICS. (#876) - The metric cardinality limit is configurable with
OTEL_METRICS_CARDINALITY_LIMIT. (#808) OTEL_SERVICE_NAMEandOTEL_RESOURCE_ATTRIBUTESoverride Relay's resource defaults, and a malformedOTEL_RESOURCE_ATTRIBUTESentry no longer discards the rest of the resource. (#815)
Status and health checks
- Per-environment status endpoints at
/status/<envId>,/status/<projectKey>/<envKey>and/status/<identifier>. (#571) - An
expectquery parameter on the status endpoints lets a health check assert on the status document and get a412response when the assertion fails.expectclauses can check every entry of a collection and count its entries. (#710, #943)
Other features
- Limit how many SDK initialization payloads Relay delivers at once with the
[Concurrency]settings (INIT_MAX_CONCURRENT,INIT_MAX_QUEUED,INIT_SEND_TIMEOUT). (#833) - When an environment's anchor SDK key changes, Relay moves the existing SDK client to the new key instead of rebuilding it. A malformed credential payload is refused and the environment keeps its current keys. (#896, #897)
- An environment recovers after LaunchDarkly rejects its SDK key. (#899)
- Redis mTLS connections, configured with
REDIS_CA_FILE,REDIS_CLIENT_CERT_FILEandREDIS_CLIENT_KEY_FILE. (#906) - Client-side responses include the resolved environment ID in the
X-LD-EnvIdheader, exposed through CORS for browser SDKs. (#648)
Performance Improvements
- Concurrent identical polling requests are deduplicated and share one response. (#798)
- FDv2 streaming and polling payloads are encoded in a single pass. (#757, #797)
Bug Fixes
- Prevent a leaked streaming connection after back-to-back malformed events. (#949)
- Keep the newest offline-mode update when a listener cannot keep up. (#960)
- Stop the server-side stream replay producer when the SDK disconnects. (#774)
- Include the basis in the FDv2 replay deduplication key, so clients with different bases no longer share a replay. (#748)
- Close the server error channel only after shutdown finishes. (#880)
- Count the legacy server-side
evalxroutes in polling request metrics. (#630) - Stop reporting response bytes that were never written. (#792)
- Update go-server-sdk to v7.21.2. (#953)
- Update golang.org/x/net to v0.62.0 to address CVE-2026-78661 and CVE-2026-97045. (#944)