Last updated: July 2026
The WildFly-based Keycloak distribution was deprecated in Keycloak 18 and removed entirely in Keycloak 20. Every release since then runs exclusively on Quarkus. If your deployment still boots from a standalone.xml file or relies on WildFly CLI scripts, you are not running an unsupported version of Keycloak — you are running a distribution that no longer exists in any release. The migration is not optional. The good news: your realm data stays intact because both distributions share the same database schema. The work is converting configuration, updating your client redirect URIs for the removed /auth path, and repackaging any custom providers from WildFly modules to plain JARs.
This guide focuses specifically on the distribution migration — switching from the WildFly runtime to the Quarkus runtime. It is distinct from a Keycloak version upgrade, though in practice you will likely do both together. If you are on Keycloak 16 or older, read the version upgrade guide first to understand the version-specific breaking changes, then use this guide for the runtime switch.
The official Keycloak documentation on Migrating to the Quarkus distribution is the authoritative reference. This guide complements it with a practical cutover runbook and real configuration examples.
Why the WildFly Distribution Was Retired
WildFly (formerly JBoss AS) is a full Java EE application server. Running Keycloak on WildFly meant shipping a complete application server runtime just to run one application. The result was large container images, 30-60 second startup times, and configuration complexity driven by WildFly internals rather than Keycloak concepts.
The Quarkus distribution, introduced as a preview in Keycloak 17, takes the opposite approach. Keycloak is compiled into a Quarkus application and ships as a self-contained binary. Startup times drop to 3-5 seconds. Container images shrink significantly. Configuration is handled by Keycloak-native options rather than WildFly XML stanzas.
Starting with Keycloak 20, the WildFly distribution stopped receiving any updates — no security patches, no bug fixes, no new features. Any deployment still on WildFly Keycloak is frozen at whatever version it was last running. The upgrade strategy guide covers how to plan the version jump in detail.
What Changed Between Distributions
The table below maps the key differences between the WildFly and Quarkus distributions. Understanding these before touching any files will prevent the most common migration mistakes.
| Concern | WildFly Distribution | Quarkus Distribution |
|---|---|---|
| Primary config file | standalone.xml / standalone-ha.xml |
conf/keycloak.conf |
| Environment variables | WildFly system properties | KC_* prefixed vars |
| CLI management tool | jboss-cli.sh |
kc.sh (Keycloak CLI) |
| Provider deployment | modules/ directory structure |
providers/ directory (plain JARs) |
| Default context path | /auth |
/ (root) |
| Docker entrypoint | /opt/jboss/keycloak/bin/standalone.sh |
kc.sh start / kc.sh start-dev |
| Clustering cache | Infinispan within WildFly | Standalone Infinispan or embedded |
| Build step required | No | Yes (kc.sh build) |
Configuration Conversion: standalone.xml to keycloak.conf
The most time-consuming part of the migration is translating WildFly XML configuration into Keycloak’s flat configuration format. Here is a representative example of a WildFly database configuration and its Quarkus equivalent.
WildFly: PostgreSQL datasource in standalone.xml
<subsystem xmlns="urn:jboss:domain:datasources:6.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/KeycloakDS"
pool-name="KeycloakDS" enabled="true">
<connection-url>
jdbc:postgresql://db:5432/keycloak
</connection-url>
<driver>postgresql</driver>
<security>
<user-name>keycloak</user-name>
<password>secret</password>
</security>
</datasource>
</datasources>
</subsystem>
Quarkus: conf/keycloak.conf
# Database
db=postgres
db-url=jdbc:postgresql://db:5432/keycloak
db-username=keycloak
db-password=secret
# HTTP
http-port=8080
https-port=8443
# Hostname
hostname=auth.example.com
hostname-strict=true
# Proxy
proxy-headers=xforwarded
Every keycloak.conf option has an equivalent KC_ environment variable. db-url becomes KC_DB_URL, hostname becomes KC_HOSTNAME, and so on. For Docker and Kubernetes deployments, environment variables are typically preferred over a mounted config file. The full option reference is at kc.sh show-config after running kc.sh build.
Startup command changes
WildFly started Keycloak with a script that loaded standalone.xml:
# WildFly startup (no longer valid)
/opt/jboss/keycloak/bin/standalone.sh
-c standalone-ha.xml
-Djboss.socket.binding.port-offset=0
The Quarkus distribution uses the kc.sh CLI with explicit modes:
# Quarkus: development mode (no TLS, permissive defaults)
kc.sh start-dev
# Quarkus: production mode (requires hostname + TLS config)
kc.sh start
--db=postgres
--db-url=jdbc:postgresql://db:5432/keycloak
--hostname=auth.example.com
--https-certificate-file=/certs/tls.crt
--https-certificate-key-file=/certs/tls.key
The build step is new and mandatory. Before starting Keycloak in production mode, run:
kc.sh build
This compiles provider JARs into the Quarkus application, generates augmented configuration, and creates an optimized startup artifact. You must re-run kc.sh build whenever you add or remove providers, change feature flags, or update database driver configuration. The Keycloak Docker Compose production setup guide shows how to integrate the build step into a container workflow.
The Removed /auth Context Path
Keycloak’s WildFly distribution served all endpoints under /auth by default. Your OIDC discovery endpoint was https://auth.example.com/auth/realms/{realm}/.well-known/openid-configuration, redirect URIs included /auth/, and admin console access was at /auth/admin.
The Quarkus distribution dropped the /auth prefix. The same discovery endpoint is now https://auth.example.com/realms/{realm}/.well-known/openid-configuration. This is the single biggest source of broken clients during migration.
Keeping /auth temporarily during cutover
You can restore the /auth prefix with a single configuration option:
# conf/keycloak.conf
http-relative-path=/auth
Or as an environment variable:
KC_HTTP_RELATIVE_PATH=/auth
Setting this lets you bring up the Quarkus distribution while all existing clients continue working without modification. Use this as a bridge during your cutover window, not as a permanent setting. Once traffic is stable on the Quarkus distribution, migrate clients off the /auth path and remove the option.
Updating clients after removing /auth
After removing http-relative-path=/auth, update every OAuth/OIDC client that hard-codes the path. The changes are mechanical:
- OIDC discovery URL: remove
/authprefix - Valid redirect URIs: remove
/authfrom any callback URIs that reference Keycloak itself (client applications redirect back to their own domains, which are unaffected) - Admin console bookmarks and monitoring URLs
Check each realm’s clients in the Keycloak admin console under Clients > {client} > Settings. The OIDC well-known endpoint can be used to verify: curl https://auth.example.com/realms/{realm}/.well-known/openid-configuration should return a 200 with the correct issuer field.
Custom Providers: From Modules to Plain JARs
WildFly used a module system for custom provider deployment. A provider required a module.xml descriptor and a specific directory structure under modules/:
modules/
system/
layers/
keycloak/
com/
example/
my-provider/
main/
my-provider.jar
module.xml
The Quarkus distribution eliminates all of this. Drop your provider JAR directly into the providers/ directory:
providers/
my-provider.jar
No module descriptor. No directory hierarchy. Keycloak discovers providers via the standard Java ServiceLoader mechanism using META-INF/services files inside your JAR. The kc.sh build step then incorporates your providers into the Quarkus augmentation.
If your provider JAR was compiled against WildFly-specific APIs (anything from org.jboss or org.wildfly packages), you will need to remove those dependencies. Providers that use only Keycloak SPI interfaces (org.keycloak.*) work without modification after repackaging.
For a complete walkthrough of the SPI system on Quarkus, including Maven project setup and deployment, see the Keycloak custom SPI development guide.
Theme migration
Themes move from themes/ under the WildFly installation to themes/ under the Quarkus installation. The directory structure and FreeMarker templates are identical. Copy your theme directories directly.
If you deploy custom themes as JARs (the recommended approach for versioned deployments), the same rule applies as for providers: drop the JAR into providers/ and run kc.sh build. Keycloak detects theme JARs via the META-INF/keycloak-themes.json descriptor inside the archive.
Clustering and Infinispan Configuration
WildFly’s Keycloak distribution embedded Infinispan inside the application server and configured it via standalone-ha.xml. Cache configuration required editing XML stanzas under the infinispan subsystem.
The Quarkus distribution supports two clustering modes:
Embedded Infinispan (default): Keycloak manages Infinispan internally. Configure cluster discovery in keycloak.conf:
# Embedded Infinispan with JDBC ping (recommended for Kubernetes)
cache=ispn
cache-stack=jdbc-ping
External Infinispan: For larger clusters or multi-site deployments, run Infinispan as a separate service and connect Keycloak to it. This is the recommended architecture for production clusters with more than three nodes.
# External Infinispan
cache=ispn
cache-remote-host=infinispan.internal
cache-remote-port=11222
cache-remote-username=keycloak
cache-remote-password=secret
The WildFly JGroups configuration and cache container XML have no direct equivalent in keycloak.conf. Translate your cache tuning (heap sizes, owners, eviction policies) into the external Infinispan server configuration, or accept the Quarkus defaults for embedded mode, which are well-tuned for typical deployments.
Database: No Schema Migration Required
This is the critical fact that makes the distribution migration safe: the WildFly and Quarkus distributions use the same database schema. Pointing the Quarkus distribution at your existing WildFly Keycloak database works. If a schema update is needed for the target version (for example, upgrading from Keycloak 16 to 26), Liquibase runs the migrations automatically on first start.
Your realm configuration, clients, users, roles, groups, identity providers, and authentication flows all survive the migration intact because they are stored in the database, not in WildFly configuration files. What you lose by removing standalone.xml is runtime configuration — hostname settings, database connection strings, HTTPS certificates — which you rebuild in keycloak.conf.
For the realm export and import patterns used during testing and environment promotion, the realm export and import strategy guide covers the tooling in detail.
Step-by-Step Cutover Runbook
This runbook assumes you are migrating a production WildFly Keycloak instance to Quarkus. Adapt timing and validation steps to your environment.
1. Take a full database backup
Before touching anything, back up your Keycloak database:
# PostgreSQL
pg_dump -h db-host -U keycloak keycloak > keycloak-backup-$(date +%Y%m%d).sql
# MySQL / MariaDB
mysqldump -h db-host -u keycloak -p keycloak > keycloak-backup-$(date +%Y%m%d).sql
Keep this backup until you have confirmed the Quarkus deployment is stable in production for at least one week.
2. Stand up Quarkus against a copy of the database
Restore the backup to a test database and point a Quarkus instance at it. This is a read-write test, so use a real copy, not a replication replica.
# Restore to test DB
createdb keycloak-test
psql keycloak-test < keycloak-backup-20260717.sql
# Start Quarkus in start-dev to verify schema migration
docker run --rm
-e KC_DB=postgres
-e KC_DB_URL=jdbc:postgresql://db-test:5432/keycloak-test
-e KC_DB_USERNAME=keycloak
-e KC_DB_PASSWORD=secret
-e KC_HTTP_RELATIVE_PATH=/auth
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin
quay.io/keycloak/keycloak:26.2
start-dev
Verify that Keycloak starts, the admin console loads at http://localhost:8080/auth/admin, and your realms, clients, and users are visible.
3. Convert and validate configuration
Create conf/keycloak.conf from your WildFly settings using the mapping table above. Run kc.sh build and then kc.sh start against the test database with your production-equivalent configuration (real hostname, real certs, real proxy settings).
Validate:
- OIDC discovery endpoint returns correct
issuer - Admin console accessible
- Token issuance works for at least one client in each realm
- Health endpoint responds:
curl http://localhost:9000/health/ready
4. Migrate custom providers and themes
Copy provider JARs to providers/. Re-run kc.sh build. Verify each provider registers correctly by checking startup logs for lines like:
KC-SERVICES0047-0: Loaded SPI EventListener provider: com.example.MyEventListener
5. Deploy Quarkus alongside WildFly with /auth bridge
Bring up the Quarkus instance with KC_HTTP_RELATIVE_PATH=/auth pointing at the production database. Route a small percentage of traffic to it (10-20%) if your load balancer supports weighted routing. Monitor logs and Keycloak metrics at /metrics.
Because both distributions share the same database, sessions created by WildFly are visible to Quarkus and vice versa. Users will not be logged out during the cutover.
6. Flip traffic and remove the /auth bridge
Once the Quarkus instance is handling 100% of traffic without errors, remove KC_HTTP_RELATIVE_PATH=/auth and update all client configurations to use the root path. Roll the Quarkus deployment to apply the change.
Monitor for 401/403 errors in application logs and for failed token validation in Keycloak’s event log (Admin Console > Events > Login Events, filtering for LOGIN_ERROR).
7. Decommission WildFly
After 24-48 hours of clean Quarkus traffic, shut down the WildFly instance. Keep the backup you took in step 1 for an additional week before deleting it.
Frequently Asked Questions
Is the WildFly Keycloak distribution still supported?
No. The WildFly-based Keycloak distribution was deprecated in Keycloak 18 and removed in Keycloak 20. It receives no security patches, bug fixes, or updates of any kind. Every Keycloak release since version 20 runs exclusively on Quarkus.
Does migrating to Quarkus require a database migration?
The WildFly and Quarkus Keycloak distributions share the same database schema. Pointing the Quarkus distribution at your existing WildFly database works without a separate schema migration step. If you are also upgrading the Keycloak version at the same time, Keycloak applies Liquibase schema migrations automatically on first start.
What happened to /auth in Keycloak?
The /auth context path was a WildFly artifact. Since Keycloak runs its own HTTP server in the Quarkus distribution rather than deploying inside a WildFly instance, the /auth prefix was unnecessary. It was removed as the default starting with the Quarkus distribution in Keycloak 17. You can restore it temporarily with KC_HTTP_RELATIVE_PATH=/auth during a migration window, but it should not remain as a permanent setting.
What happened to jboss-cli.sh?
jboss-cli.sh was the WildFly management CLI and has no equivalent in the Quarkus distribution. There is no runtime management interface. Configuration changes require updating keycloak.conf or environment variables and restarting the process. For dynamic changes (adding providers, changing feature flags), run kc.sh build and restart. Operational tasks like realm management use the Admin REST API.
Do custom WildFly modules need to be rewritten?
Custom providers that depend only on Keycloak SPI interfaces (org.keycloak.*) do not need code changes. Remove the module.xml descriptor, discard the WildFly directory structure, and place the JAR directly in providers/. Providers that depend on WildFly-specific APIs (org.jboss.*, org.wildfly.*) need those dependencies removed. In practice, most Keycloak extensions do not use WildFly internals and migrate without code changes.
Managed Keycloak Without the Migration Overhead
The WildFly-to-Quarkus migration is a one-time cost, but ongoing Keycloak operations — version upgrades, cluster management, provider deployments, database maintenance — continue to accumulate. If you would rather focus on your product than on Keycloak operations, Skycloak runs fully managed Keycloak clusters on the current Quarkus distribution, handles version upgrades, and supports custom provider deployment through a straightforward deployment pipeline.
The upgrade cluster strategy guide is a useful follow-up once you have completed the distribution migration and are ready to plan your next version upgrade.