# 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 extends ExecutorService>)`, `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.