A Developer’s Guide to Surviving the Apicurio v3 SDK Migration
Change one dependency, and your Apicurio client quietly calls a URL that returns 404. Here is how to migrate without hitting that.
TL;DR
- Who this is for: Java apps using
apicurio-registry-v2-java-sdk - What changes: Maven artifact, factory class, imports, base URL
- The pitfall: a stale
/v2base URL becomes a doubled path
Why migrate now
Migrating an enterprise codebase to a new major version is rarely a simple find-and-replace — especially when the legacy SDK is officially slated for removal. Apicurio Registry is a CNCF Sandbox project that enterprises use to manage API schemas and artifacts. As part of its move from REST API v2 to v3, the legacy client-v2 Java SDK module is deprecated and will be removed in a future release.
All new usage should target the v3 client module (RegistryClientFactory). If your application currently uses the Kiota-generated client-v2 module (Maven artifact apicurio-registry-v2-java-sdk), you will need to migrate before the module is removed.
Which SDK are you using?
This guide covers the Kiota-generated client-v2 module (apicurio-registry-v2-java-sdk). If you use the legacy apicurio-registry-client 2.6.13.Final, follow the REST API and SDK client section of the official v2 to v3 migration docs instead. official v2 to v3 migration PR
The steps below cover the Java SDK swap and one configuration pitfall.
Before you start
Before updating your application, ensure you have:
- An existing Java project using the Apicurio Registry v2 Java SDK.
- Access to your project’s
pom.xmlorbuild.gradlefile. - Your Apicurio Registry server updated to v3.
Migration steps
Step 1: Update Your Maven Dependency
First, you need to swap the artifact ID in your build configuration.
Before (v2 SDK):
<dependency>
<groupId>io.apicurio</groupId>
<artifactId>apicurio-registry-v2-java-sdk</artifactId>
<version>${apicurio-registry.version}</version>
</dependency>After (v3 SDK):
<dependency>
<groupId>io.apicurio</groupId>
<artifactId>apicurio-registry-java-sdk</artifactId>
<version>${apicurio-registry.version}</version>
</dependency>Step 2: Swap the Factory and Client Imports
The v3 SDK mirrors the v2 SDK’s factory API, so the factory swap is mechanical. The generated client types and request builders differ, so Step 4 covers your call sites. While RegistryClientOptions is a shared class in both SDKs, the generated RegistryClient types differ between versions (io.apicurio.registry.rest.client.v2.RegistryClient vs. io.apicurio.registry.rest.client.RegistryClient).
Get Riyasaharan’s stories in your inbox
Join Medium for free to get updates from this writer.
You will need to update your imports and the factory class name.
Before:
import io.apicurio.registry.client.RegistryV2ClientFactory;
import io.apicurio.registry.client.common.RegistryClientOptions;
import io.apicurio.registry.rest.client.v2.RegistryClient;
RegistryClientOptions options = RegistryClientOptions.create("http://localhost:8080/apis/registry/v2");
RegistryClient client = RegistryV2ClientFactory.create(options);After:
import io.apicurio.registry.client.RegistryClientFactory;
import io.apicurio.registry.client.common.RegistryClientOptions;
import io.apicurio.registry.rest.client.RegistryClient;
RegistryClientOptions options = RegistryClientOptions.create("http://localhost:8080/apis/registry/v3");
RegistryClient client = RegistryClientFactory.create(options);Step 3: Update the Base URL (Avoiding the Doubled-Path 404 Error)
This is a required step. The base URL passed into RegistryClientOptions must change from /apis/registry/v2 to /apis/registry/v3.
The Pitfall: RegistryClientRequestAdapterFactory normalizes the URL by checking whether it already ends with the target version’s path. If it doesn’t, the factory appends that suffix. It does not detect or strip a stale v2 suffix.
If you switch to RegistryClientFactory but leave a stale …/apis/registry/v2 URL in place, the client will not fail fast. Instead, it silently produces a doubled, invalid path (…/apis/registry/v2/apis/registry/v3), causing your requests to throw 404 Not Found errors at call time. Always update your base URL string alongside the factory swap.
RegistryClientOptions also carries your auth, TLS, and custom headers. These are shared unchanged between the v2 and v3 SDKs, so only the base URL changes.
Step 4: Review your API calls
REST API v3 is not a drop-in replacement for v2. Check call sites that reference artifact groups, use endpoints that were renamed or removed, or parse response payloads directly. The OpenAPI spec for v3 is the source of truth.
How to confirm it worked:
Start the app against a v3 registry and make one read call, such as listing artifacts. A 200 response means the URL is correct. A 404 on a path containing /v2/…/v3 means a stale base URL.
Quick reference
What the review taught me
I wrote this guide for PR #9390 on Apicurio Registry, as part of my LFX Mentorship application.
My first draft had two problems I did not see. Every code fence used escaped backticks, so none of the examples rendered on GitHub. And I called the migration a find-and-replace without saying the base URL must change too.
Reviewers caught both. I fixed the fences and added a dedicated base URL step. A second reviewer then traced validateAndNormalizeRegistryUrl and confirmed the doubled-path failure. Later I narrowed the “mechanical” claim, because the generated client types differ between v2 and v3. I also folded an “update auth config” section into Step 3, since its body said nothing needed to change.
Two smaller items from the same PR:
- The deprecation uses
@Deprecated(forRemoval = true) with method-level@SuppressWarnings(“removal”)at 22 call sites across 7 files. - A License Compliance failure also reproduced on main, so a reviewer pointed it out and I opened #9622 to track it separately.
What I would do differently: preview Markdown before opening the PR, and check every “required” step against its example before writing prose around it.
Thanks to @paoloantinori and @aclfe for the reviews. The PR merged on Sep 4.
About the Author
Hi, I am Riya Saharan, an AI & Data Science B.Tech student, open-source contributor, and technical writer. I am passionate about simplifying complex systems through clear documentation.





