# 27 Upgrade Use this guide to upgrade a Helidon 4 application to Helidon 27. ## Before You Start 1. Upgrade to latest Helidon 4.5.x release. 2. Build and test with JDK 27. 3. Remove deprecation warnings in your Helidon 4 build. 4. Inventory dependencies that start with `io.helidon.microprofile`, `io.helidon.jersey`, `io.helidon.lra`, and `io.helidon.integrations`. 5. Check whether each `io.helidon.integrations` dependency has a replacement in the [Helidon Extensions](https://github.com/helidon-io/helidon-extensions) repository. ## MicroProfile MicroProfile support has been decoupled from Helidon and now releases independently from [Helidon MicroProfile](https://github.com/helidon-io/helidon-microprofile). MicroProfile support is not available for Helidon 27 at this time. If your application uses Helidon MP, CDI, JAX-RS, or MicroProfile specification APIs, keep that application on Helidon 4.5.x until the independent MicroProfile release is available. Do not upgrade those workloads to Helidon 27 unless you are also replacing the MP programming model with Helidon Core APIs. ## Java Helidon 27 requires Java 27. Update: - Maven and Gradle toolchains - CI images - Runtime container images - Native image builds - `maven-compiler-plugin` or Gradle Java language settings ## Dependencies Import the Helidon 27 BOM to update Helidon dependencies to the same version. Then remove dependencies for modules that are no longer present: - `helidon-mp` - `helidon-microprofile*` - `helidon-jersey*` - `helidon-lra*` - `helidon-integrations*` - `helidon-tracing-providers-jaeger` - `helidon-tracing-providers-zipkin` - `helidon-tracing-providers-opentracing` - `helidon-tracing-exporter-jaeger` - `helidon-metrics-prometheus` - `helidon-cors` - `helidon-http-media-gson` - `helidon-security-abac-policy-el` - `helidon-security-providers-google-login` - `helidon-security-providers-config-vault` - `helidon-webserver-service-common` Use these replacements where applicable: - CORS: `io.helidon.webserver:helidon-webserver-cors` - Metrics endpoint: `helidon-webserver-observe-metrics` - Tracing: `helidon-tracing-providers-opentelemetry` - Former integrations: use the matching Helidon Extensions release when one is available For Gson media support and the removed security providers, follow the migration steps under [JSON](#json) and [Security](#security). Applications using `helidon-webserver-service-common` must also update their service implementations as described under [WebServer](#webserver). Existing SE messaging applications must migrate their API usage and connector dependencies as described under [Messaging](#messaging). ## Extensions Helidon 27 no longer releases the former `io.helidon.integrations` artifacts from the Helidon repository. Supported integrations are moving to independent releases from [Helidon Extensions](https://github.com/helidon-io/helidon-extensions). Import the extension-specific BOM and replace the old coordinates with the new extension coordinates. Each extension is versioned independently. For most replacement artifacts, apply this rule: - In the group ID, replace `io.helidon.integrations` with `io.helidon.extensions`. - In the artifact ID, replace `helidon-integrations` with `helidon-extensions`. For example: ```xml io.helidon.extensions.neo4j helidon-extensions-neo4j ``` The exceptions are: | Integration | Replacement rule | | --- | --- | | Eureka discovery | Use `io.helidon.extensions.eureka:helidon-extensions-eureka-discovery` when you need only the Eureka discovery provider. | | OCI | Add `v3` to the group ID and artifact ID. For example, use `io.helidon.extensions.oci.v3:helidon-extensions-oci-v3`. | | Vault | Replace `vault` with `hashicorp.vault` in the group ID and `hashicorp-vault` in the artifact ID. For example, use `io.helidon.extensions.hashicorp.vault:helidon-extensions-hashicorp-vault`. | Extensions are released on independent schedules. All extensions might not be available initially, but they will be released over time and new extensions will be added. ## Helidon Core APIs Most Helidon Core APIs remain compatible with Helidon 4.5.x code. The most common source changes are from deprecated APIs that were removed in Helidon 27. Make these changes before upgrading: - Replace `Header.value()` with `Header.get()`. - Replace `HostValidator` with `io.helidon.common.uri.UriValidator`. - Replace common config bridge usage with `io.helidon.config.Config`. - Replace static metrics helper calls with injected `MeterRegistry` or, in imperative application code, `Services.get(MeterRegistry.class)`. - Replace static metrics factory calls with injected `MetricsFactory` or, in imperative application code, `Services.get(MetricsFactory.class)`. - Replace tracing global accessors with injected `Tracer` or, in imperative application code, `Services.get(Tracer.class)`. - Replace direct builder constructors with static `builder()` or `create(...)` methods. After upgrading to Helidon 27, replace old TLS reload APIs that accept `Tls` with `TlsMaterial`. `TlsMaterial` is new in Helidon 27 and is not available in Helidon 4.x. ## Service Registry `@Service.Provider` is removed. Replace it with a service scope annotation, such as `@Service.Singleton` or `@Service.PerLookup`, that preserves the intended lifetime of the service. A class with an `@Service.Inject` constructor is also discovered as a service; without an explicit scope it uses `@Service.PerLookup`. See [Defining Services](../../modules/injection/injection.md#how-are-services-defined). Services created by the registry must obtain dependencies through injection. Do not replace a static metrics or tracing accessor inside a registry-created service with `Services.get(...)`. If that service needs programmatic lookup, inject `ServiceRegistry` and use that instance. This restriction applies during construction, lifecycle callbacks, and normal service methods. ## Config Update providers and mapping code to use `io.helidon.config.Config`, not `io.helidon.common.config.Config`. `Config.global(Config)` and `io.helidon.common.config.GlobalConfig` are removed. For imperative application bootstrap, replace: ```java Config.global(config); ``` with: ```java Services.set(Config.class, config); ``` Register the configuration before any service resolves it. `Config.global()` now returns the `Config` from the current service registry. If the application uses a custom registry, register the configuration with that registry. Inside registry-created services, inject `Config` instead of using either global accessor. These registration changes can be made while still on Helidon 4.5.x. ## JSON ### Gson Media Support Gson media support moves to Helidon Extensions, with a release planned after Helidon 27. Replace `io.helidon.http.media:helidon-http-media-gson` with `io.helidon.extensions.gson:helidon-extensions-gson-media` when that extension release is available. Update explicit `GsonSupport` imports to `io.helidon.extensions.gson.media.GsonSupport`. See the [Gson extension documentation](https://github.com/helidon-io/helidon-extensions/blob/main/extensions/gson/docs/README.md) for the extension version, configuration, and registration details. ### JWT and JWK JSON-P APIs The deprecated JWT and JWK overloads using `jakarta.json` are removed. Replace them with the APIs using `io.helidon.json` before upgrading; the replacements are available in Helidon 4.5.x. | Helidon 4 API | Replacement | | --- | --- | | `Jwt.headerClaim(name)` | `Jwt.headerClaimValue(name)` | | `Jwt.payloadClaim(name)` | `Jwt.payloadClaimValue(name)` | | `Jwt.payloadClaims()` | `Jwt.payloadClaimsJson()` | | `Jwt.headerJson()` | `Jwt.headerJsonObject()` | | `Jwt.payloadJson()` | `Jwt.payloadJsonObject()` | | `Jwk.create(jakarta.json.JsonObject)` | `Jwk.create(io.helidon.json.JsonObject)` | Update imports and code that reads or constructs the JSON values returned or accepted by these methods. The Helidon and Jakarta JSON types are distinct; they cannot be cast to each other. This change does not remove the separate `helidon-http-media-jsonp` and `helidon-http-media-jsonb` modules. ## WebServer If you use Unix domain sockets, move the socket path from `bind-address` to `bindings.uds.socket`. Example: ```yaml server: bindings: tcp: enabled: false uds: socket: "/var/run/my-service.sock" required: true ``` Use `connectionOptions()` instead of removed listener connection config helpers. Use `maxConnections()` instead of `maxTcpConnections()`. The `helidon-webserver-service-common` module and its `RestServiceSettings`, `FeatureSupport`, and `HelidonFeatureSupport` APIs are removed. Implement custom services directly with `HttpService` and custom HTTP features with `HttpFeature`, preserving their route and context-path configuration. Move service-specific CORS setup to the WebServer `CorsFeature` or its `cors` configuration. See [CORS](../../modules/cors.md). ### HTTP Method Case Sensitivity Helidon 27 preserves HTTP method text exactly and matches method selectors case-sensitively, with temporary compatibility for the security configuration listed below. Before upgrading, enable case-sensitive wire parsing on every Helidon 4.5.x listener and test the application with its actual clients: ```yaml [application.yaml] server: case-sensitive-methods: true ``` In Helidon 4.5.x this option affects only inbound HTTP/1.1 and HTTP/2 wire parsing; configured method selectors retain the 4.x compatibility normalization. At the same time, replace lowercase or mixed-case built-in method names such as `get` with their standard uppercase form such as `GET` in all configuration. This prepares those selectors for the case-sensitive behavior in Helidon 27. Update at least the following: - WebServer security path `methods` - security provider outbound target `methods` - HTTP signature `sign-headers` method entries and signing outbound targets - automatic metrics path `methods` and tracing path `methods` - WebClient metric `methods` - CORS `allow-methods` To ease migration, Helidon 27 temporarily retains compatibility when loading WebServer security path `methods`, security provider outbound target `methods`, and inbound or outbound HTTP signature `sign-headers` method selectors from configuration. A non-uppercase known method matches both the exact configured token and its uppercase form. For example, `get` matches `get` and `GET`, but does not match `Get`; `PoSt` matches `PoSt` and `POST`, but does not match `post`. The known methods are `GET`, `POST`, `QUERY`, `PUT`, `DELETE`, `HEAD`, `PATCH`, `OPTIONS`, `TRACE`, and `CONNECT`. An already uppercase method matches only that token, and a custom method such as `Follow` remains exact. For HTTP signature `sign-headers`, an explicit uppercase entry overrides any generated compatibility entry regardless of configuration order. Without an explicit uppercase entry, the last configured case variant supplies the signed headers for their shared uppercase entry. Security path method lists ignore duplicates; absent or empty lists continue to match all methods. Loading a non-uppercase known method in these security settings logs a warning. This compatibility will be removed in a future major version, when all method selectors will match only their exact configured token. Use uppercase names now for standard methods. This compatibility applies only to the security configuration listed above. Programmatic builder selectors, runtime HTTP method parsing, and selectors in other modules remain case-sensitive. A programmatic selector for `get` matches only the distinct lowercase method `get`, not `GET`. OpenTelemetry server metrics and spans classify only exact known method names; case variants are reported as `_OTHER`, and spans preserve the received token in `http.request.method_original`. `Method.createCaseSensitive(String)` is retained as an alias for compatibility with Helidon 4 and is deprecated for removal. Use `Method.create(String)` on Helidon 27; both methods preserve the exact method text. The HTTP signatures provider continues to implement the legacy `draft-cavage-http-signatures-03` `(request-target)` canonicalization, which lowercases the method before signing. That signed component therefore does not distinguish method case. The temporary compatibility for security configuration does not change this canonicalization. ## Messaging Helidon 4 SE messaging used MicroProfile Reactive Messaging types and Reactive Streams. Helidon 27 replaces that implementation under the same `io.helidon.messaging:helidon-messaging` coordinates. Existing SE messaging applications require source and configuration changes; updating the dependency version alone is insufficient. After upgrading the messaging dependency: - Replace `Messaging.builder()` and `Channel` topology construction with `MessagingGraph.builder()` and the graph's named channels. Start and close the resulting `MessagingGraph` as part of the application's lifecycle. - Replace `Emitter.create(...)` with an emitter obtained from the graph or injected for a named channel. Replace `Emitter.send(...)` with `emit(...)`. The new call completes synchronously when the required outputs have completed; it does not return a `CompletionStage`. Adapt asynchronous completion callbacks and error handling accordingly. - Replace MicroProfile `Message` values with `io.helidon.messaging.Message`. Use `Message.create(...)` instead of `Message.of(...)`, and `entity()` instead of `getPayload()`. The new message has no `ack()` or `nack()` callbacks. Handlers must finish their delivery work before returning and throw on failure; transport acknowledgement is the connector's responsibility. - Replace `mp.messaging.*` configuration with the `messaging` configuration model. Declare named connector instances under `messaging.connector`, each with a `type`, then reference an instance name from `messaging.incoming..connector` or `messaging.outgoing..connector`. This requires adapting the connector configuration, not only renaming the top-level key. - When loading graph configuration programmatically, pass the `messaging` subtree: `.config(rootConfig.get("messaging"))`. - Replace old `helidon-messaging-*` connector artifacts with compatible connectors from Helidon Extensions. Select a connector release built for the new messaging API and follow that release's dependency and configuration documentation; the old connectors are not binary-compatible replacements. For imperative topologies, replace `.listener(...)` with `.payloadSink(...)` and the payload-mapping `.processor(...)` overload with `.payloadProcessor(...)`. Topologies using `.publisher(...)`, `.subscriber(...)`, or the reactive `.processor(...)` overloads must also be rewritten. The graph no longer accepts Reactive Streams publishers, subscribers, or processors: - Rewrite publishers as `java.util.stream.Stream` sources registered with `.payloadSource(...)` or `.messageSource(...)`, or produce messages through a graph emitter. - Rewrite subscribers as synchronous consumers registered with `.payloadSink(...)` or `.messageSink(...)`. - Rewrite reactive processors as synchronous per-item mappings registered with `.payloadProcessor(...)` or `.messageProcessor(...)`. Adapt reactive operators and asynchronous completion to these synchronous contracts; these changes require more than renaming the builder methods. Custom connectors must implement the new messaging connector and channel SPI. Review retry handling: outputs that completed before a later output failed are not rolled back, so retrying a delivery can repeat their effects. See the [Messaging API and configuration documentation](https://github.com/helidon-io/helidon/blob/main/messaging/README.md) for graph construction, delivery handling, and connector configuration. If a required compatible connector is not yet available, keep that application on Helidon 4.5.x until the connector migration can be completed. ## Metrics Helidon 27 uses Micrometer-backed metrics for Helidon Core. The old Prometheus Java client integration is removed. Change code as follows: - Inject or look up `MeterRegistry`. - Use meter tags instead of scopes. - Use `/observe/metrics` as the canonical metrics endpoint. - Treat `/observe/metrics/application`, `/observe/metrics/base`, and `/observe/metrics/vendor` as compatibility paths only. - Look up `gc.time` as a `Gauge`. - Replace `metrics.rest-request-enabled` with `metrics.rest-request.enabled`. - Remove `metrics.gc-time-type`. `metrics.scoping` no longer controls meter registration or output, and the `scope` query parameter is ignored. The legacy scope-specific endpoint paths return the same unscoped metrics as `/observe/metrics`. Applications that used scope settings to disable meters or select exported data must replace those rules and update their scrape configuration; retaining the old settings can expose meters that were previously excluded. Use ordinary meter tags for classification and implement the corresponding selection in the metrics integration. See [Metrics Scopes](../../modules/metrics/metrics.md#metrics-scopes) for the customization and formatter APIs. ## Tracing Use OpenTelemetry. Remove Jaeger, Zipkin, and OpenTracing Helidon provider dependencies. Also remove `io.helidon.tracing:helidon-tracing-exporter-jaeger` if the application uses the Helidon Jaeger gRPC exporter. It is removed independently of the Jaeger tracing provider. Configure an OpenTelemetry exporter and update the collector endpoint and protocol to match the selected exporter. Prefer OTLP export. OpenTelemetry Java 1.65 no longer publishes the Zipkin exporter. If imperative application bootstrap owns the OpenTelemetry instance, register it before any tracer lookup: ```java Services.set(OpenTelemetry.class, openTelemetry); ``` Then inject `Tracer` into registry-created services. Imperative application code can use: ```java Tracer tracer = Services.get(Tracer.class); ``` ## Security HTTP Digest authentication is removed. Replace it with OIDC, HTTP Basic, header assertion, or HTTP signatures. If you use JWT Provider, plan extra validation. It is retained but is no longer evolved. The following providers are also removed. Migrate any application that depends on them before upgrading: | Removed provider | Required application change | | --- | --- | | ABAC policy EL (`helidon-security-abac-policy-el`) | Replace EL policy evaluation with an application-supplied `PolicyExecutor` or equivalent authorization logic that preserves the existing rules. The policy validator API remains available, but its former EL executor does not. | | Google Login (`helidon-security-providers-google-login`) | Replace `GoogleTokenProvider` and its `google-login` provider configuration with a supported authentication provider, such as OIDC, and adapt token validation and identity mapping. | | Config Vault (`helidon-security-providers-config-vault`) | Replace the `config-vault` provider with the HashiCorp Vault extension's secrets and encryption providers, or an application-specific implementation. Update provider configuration and API usage as described below. | The HashiCorp Vault extension provides KV1, KV2, and Cubbyhole security providers for secrets, and a Transit security provider for encryption. See the [Vault extension documentation](https://github.com/helidon-io/helidon-extensions/blob/main/extensions/hashicorp-vault/docs/README.md) for dependencies and setup. Migrating from `ConfigVaultProvider` requires moving config-backed secrets to Vault and updating secret paths and key configuration. Migrate existing encrypted data before removing the old provider; the extension uses Vault's keys and ciphertext format. ## DB Client If your application has a JPMS descriptor and uses Hikari DB client metrics, change: ```java requires helidon.dbclient.metrics.hikari; ``` to: ```java requires io.helidon.dbclient.metrics.hikari; ``` Maven coordinates and Java packages are unchanged. ## Other API Changes Review these additional changes before upgrading: - WebClient: deprecated compatibility methods are removed from connection, DNS, and HTTP client configuration APIs. - Fault Tolerance: deprecated helpers such as `FaultTolerance.config(io.helidon.common.config.Config)`, `executor(Supplier)`, `toDelayedRunnable(...)`, and `toDelayedCallable(...)` are removed. - Fault Tolerance: if both `delay-factor` and absolute `jitter` are configured, Helidon 27 applies the delay factor first and then jitter. Earlier releases ignored `jitter` in that case. - gRPC: deprecated helper APIs such as `CollectingObserver` and `ResponseHelper` are removed. - GraphQL: `@GraphQl.Subscription` is deprecated. Subscription execution is reserved for future use and is ignored. - Feature metadata: top-level `Aot`, `Feature`, `Incubating`, and `Preview` annotations are removed. Use nested annotations in `io.helidon.common.features.api.Features`. ## Deprecated APIs Helidon 27 still contains deprecated APIs that compile but should not be used in new code. Treat these as upgrade cleanup items: - Metrics scopes and scope-aware registry methods - Static metrics factory and lifecycle methods - Static meter builders and factory methods - Tracing global accessors and wrapper aliases - TLS reload methods that accept `Tls` - Security and DB client direct builder constructors - Old time-unit overloads in reactive, file watcher, and health APIs - Old config date and time mappers for `Date`, `Calendar`, `TimeZone`, and related types - `SecurityContext.atzChecked()` - HTTP/1 split receive and send logging accessors - `BufferData.asInputStream()` - `HeaderNames.TSV_NAME` and `HeaderNames.TSV` Compile with deprecation warnings enabled and replace these APIs before relying on them for long-lived Helidon 27 code. ## Third-Party Libraries Review direct use of these managed libraries: | Library | Helidon 4.5.x | Helidon 27 | Compatibility notes | | --- | --- | --- | --- | | HikariCP | 5.0.1 | 7.1.0 | Validate pool behavior and metrics. HikariCP 6 changed some connection eviction and metrics behavior. | | Micrometer | 1.15.12 | 1.17.1 | Prometheus duplicate meter names are stricter. Duplicate time series errors now use the Prometheus Java client exception type. | | Micrometer Prometheus | 1.15.2 | 1.17.1 | Review custom Prometheus naming conventions and any direct Prometheus Java client usage. | | OpenTelemetry | 1.62.0 | 1.65.0 | Zipkin exporter publishing stopped in OpenTelemetry Java 1.65. Prometheus reader constructors and some SPI property names changed in earlier 1.63 and 1.64 releases. | | OpenTelemetry semantic conventions | 1.37.0 | 1.43.0 | Review code that uses semantic convention constants directly. | | Protobuf | 4.31.1 | 4.36.0 | Regenerate gRPC or protobuf classes with a matching `protoc` version if your build pins code generation. | | ASM | 9.8 | 9.10.1 | Usually build-time only. Recheck custom bytecode tooling. | Regenerate protobuf or gRPC classes if your build pins `protoc` or generated sources. Review custom Prometheus meter names for duplicate effective names. Review code that uses OpenTelemetry alpha, incubating, or SPI APIs directly. ## GraalVM Native Image The `native-image` Maven profile in example application poms has been removed. Considering using the `jlink-image` profile which now supports the JDK AOT Cache. ## Final Checks 1. Run with JDK 27. 2. Run tests with deprecation warnings enabled. 3. Check startup logs for missing service providers. 4. Check `/observe/health` and `/observe/metrics`. 5. Check tracing export in your collector. 6. Check container and custom Java runtime image builds.