Edit this Page

HTTP/3 Reference

HTTP/3 support is experimental. Configuration properties and behavior may change in future releases.

1. Overview

HTTP/3 is the latest version of the HTTP protocol. It replaces TCP with QUIC, a transport protocol built on UDP that provides built-in encryption, reduced connection setup latency, and elimination of head-of-line blocking.

From an application perspective, HTTP/3 is transparent: request and response handling is identical to HTTP/1.1 and HTTP/2. The same handlers, filters, and endpoints work across all three protocols. The only differences are at the transport level — QUIC uses UDP instead of TCP, and TLS 1.3 is mandatory.

Quarkus serves HTTP/1.1, HTTP/2, and HTTP/3 on the same port. Clients discover HTTP/3 availability through the Alt-Svc response header on HTTP/1.1 and HTTP/2 responses, then upgrade to QUIC/UDP for subsequent requests.

2. Getting started

Add the quarkus-http3 extension to your project:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-http3</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-http3")

HTTP/3 requires TLS. In dev and test mode, a TLS certificate is auto-generated if none is configured (see Auto-TLS in dev and test mode). In production, you must configure TLS explicitly — see the TLS registry reference for details.

With TLS in place, HTTP/3 is enabled automatically. No additional configuration is needed.

3. Configuration

Configuration property Type Default Description

quarkus.http3.enabled

boolean

true

Whether HTTP/3 (QUIC) support is enabled. When enabled and the native QUIC library is on the classpath, HTTP/3 is added to the set of supported HTTP versions on the HTTPS server.

quarkus.http3.alt-svc

boolean

true

Whether to add the Alt-Svc response header to HTTP/1.1 and HTTP/2 responses on the HTTPS server, advertising HTTP/3 availability. The header value follows the format h3=":PORT"; ma=MAX_AGE.

quarkus.http3.alt-svc-max-age

Duration

24H

The max-age value included in the Alt-Svc header. Tells clients how long to cache the HTTP/3 advertisement before re-checking via HTTP/1.1 or HTTP/2. Only effective when quarkus.http3.alt-svc is true.

4. Auto-TLS in dev and test mode

When the HTTP/3 extension is on the classpath and no TLS configuration is detected, Quarkus auto-generates a certificate in dev and test mode:

  • If the Quarkus Dev CA exists at ~/.quarkus/quarkus-dev-root-ca.pem, the certificate is signed by it. Browsers and clients that trust the Dev CA will accept the certificate without warnings.

  • Otherwise, a self-signed certificate is generated. Browsers will show a certificate warning, which is acceptable for development.

Run quarkus tls generate-quarkus-ca --install to create the Dev CA and install it in your system trust store for the best developer experience.

When auto-TLS is active, plain HTTP requests are redirected to HTTPS by default. To allow plain HTTP alongside HTTPS, set:

quarkus.http.insecure-requests=enabled

In production mode, no auto-generation occurs. If TLS is not configured, the server fails at startup with a clear error message.

5. Native QUIC library

HTTP/3 relies on Quiche, a native QUIC implementation provided through Netty. The library is platform-specific: a separate artifact is required for each OS and CPU architecture combination.

The following variants are available:

Platform Classifier

Linux x86_64

linux-x86_64

Linux aarch64

linux-aarch_64

macOS x86_64

osx-x86_64

macOS aarch64 (Apple Silicon)

osx-aarch_64

Windows x86_64

windows-x86_64

5.1. Automatic dependency selection (Maven only)

When you add the quarkus-http3 extension with Maven, the native QUIC library matching your build-time OS and architecture is included automatically using Maven profile activation. No manual dependency configuration is needed for typical development and single-platform deployments.

Gradle does not support conditional profile activation. Gradle users must always declare the native QUIC dependency manually — see Adding the native QUIC dependency (Gradle).

5.2. Adding additional platform dependencies (Maven)

If you build on one platform but deploy to another (for example, building on macOS but deploying to Linux), you need to explicitly add the dependency for the target platform:

pom.xml
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-codec-native-quic</artifactId>
    <classifier>linux-x86_64</classifier>
</dependency>

You can add as many platform variants as needed. The extension detects available libraries at build time and logs which variants were found.

5.3. Excluding the automatic dependency (Maven)

If you want full control over which native library variants are included, you can exclude the automatic selection and list them explicitly:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-http3</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.netty</groupId>
            <artifactId>netty-codec-native-quic</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- Manually select the platform(s) you need -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-codec-native-quic</artifactId>
    <classifier>linux-x86_64</classifier>
</dependency>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-codec-native-quic</artifactId>
    <classifier>linux-aarch_64</classifier>
</dependency>
If you exclude the automatic dependency, you must provide at least one platform variant manually. The server will fail to start if no native QUIC library is found on the classpath.

5.4. Adding the native QUIC dependency (Gradle)

Gradle does not support Maven profile activation, so the native QUIC library is not selected automatically. You must always add the dependency for your target platform(s) explicitly:

build.gradle
implementation("io.quarkus:quarkus-http3")

// Add the native QUIC library for your platform(s)
implementation("io.netty:netty-codec-native-quic::linux-x86_64")

If you build and deploy on the same platform, add only that platform’s classifier. If you build on one platform but deploy to another, add both:

build.gradle
implementation("io.quarkus:quarkus-http3")

// Build platform (e.g., macOS) + deployment platform (e.g., Linux)
implementation("io.netty:netty-codec-native-quic::osx-aarch_64")
implementation("io.netty:netty-codec-native-quic::linux-x86_64")

6. How it works

6.1. Same port, dual transport

The Quarkus HTTP server listens on the HTTPS port (default 8443) for both TCP (HTTP/1.1, HTTP/2) and UDP (HTTP/3 over QUIC) traffic. There is no separate port for HTTP/3.

6.2. Alt-Svc discovery

When HTTP/3 is enabled, the server automatically adds an Alt-Svc header to HTTP/1.1 and HTTP/2 responses:

Alt-Svc: h3=":8443"; ma=86400

This tells clients that HTTP/3 is available on the same port. Browsers and HTTP clients that support HTTP/3 will upgrade to QUIC for subsequent requests.

To disable the Alt-Svc header:

quarkus.http3.alt-svc=false

6.3. Transparent to application code

HTTP/3 does not change how you write application code. The same Jakarta REST resources, Vert.x routes, filters, and interceptors work across all HTTP versions. You can check the protocol version of a request using HttpServerRequest.version() if needed.

7. Using HTTP/3 with the REST Client

The Quarkus REST Client can connect to HTTP/3 servers. To enable HTTP/3 for a specific client, set:

quarkus.rest-client.my-client.http3=true

To enable HTTP/3 for all REST clients:

quarkus.rest-client.http3=true

The target server must support HTTP/3 and the connection must use TLS. Make sure the client’s TLS configuration trusts the server’s certificate:

quarkus.rest-client.my-client.url=https://my-server:8443
quarkus.rest-client.my-client.http3=true
quarkus.rest-client.tls-configuration-name=my-tls-config

See the REST Client guide for more details on REST Client configuration.

8. Limitations

  • Experimental — This feature is under active development. APIs and behavior may change.

  • UDP in containers — HTTP/3 uses UDP. If your application runs in a container (Docker, Kubernetes), ensure UDP port forwarding is configured for the HTTPS port. Some corporate firewalls may also block UDP traffic.

  • No WebSocket over HTTP/3 — WebSocket connections use HTTP/1.1 or HTTP/2. This is a Vert.x limitation, not specific to Quarkus.

  • Native image — HTTP/3 requires a platform-specific native QUIC library (netty-codec-native-quic). The correct classifier for your platform must be on the classpath.

9. Verifying your HTTP/3 setup

9.1. Using curl

If your curl build supports HTTP/3 (check with curl --version — look for HTTP3 in the features list):

curl --http3 -k https://localhost:8443/hello

The -k flag skips certificate verification (useful with self-signed certificates in dev mode).

9.2. Using browser DevTools

Open your browser’s developer tools, go to the Network tab, and enable the Protocol column. Requests served over HTTP/3 will show h3.

9.3. Using the Vert.x HTTP client

You can verify HTTP/3 programmatically using the Vert.x HTTP client:

Vertx vertx = ...; // Inject or obtain the Vert.x instance
int port = 8443;

HttpClientConfig clientConfig = new HttpClientConfig();
clientConfig.setVersions(HttpVersion.HTTP_3);
clientConfig.setHttp3Config(new Http3ClientConfig());

ClientSSLOptions sslOptions = new ClientSSLOptions()
        .setTrustAll(true); // For dev mode only

HttpClientAgent client = vertx.httpClientBuilder()
        .with(clientConfig)
        .with(sslOptions)
        .build();

client.request(HttpMethod.GET, port, "localhost", "/hello")
        .compose(HttpClientRequest::send)
        .compose(resp -> {
            System.out.println("Protocol: " + resp.version()); // HTTP_3
            return resp.body();
        })
        .compose(body -> {
            System.out.println("Body: " + body);
            return client.close();
        })
        .await(10, TimeUnit.SECONDS);