Skip to main content
The latest major version of the algoliasearch package is version 4. This page helps you upgrade from version 3 and explains the breaking changes you need to address. Algolia generates the version 4 clients from OpenAPI specifications, which provides consistent behavior across all languages and up-to-date API coverage. The main architectural change is the removal of the initIndex pattern: all methods are now on the client instance directly, with indexName as a parameter. For the full list of changes, see the Java changelog.

Update your dependencies

Version 4 consolidates the separate algoliasearch-core and HTTP client packages into a single algoliasearch artifact. You no longer need algoliasearch-apache or algoliasearch-java-net.

Maven

Replace your Algolia dependencies in pom.xml:
pom.xml
<!-- version 3 -->
<dependency>
  <groupId>com.algolia</groupId>
  <artifactId>algoliasearch-core</artifactId>
</dependency>
<dependency>
  <groupId>com.algolia</groupId>
  <artifactId>algoliasearch-apache</artifactId>
</dependency>

<!-- version 4 -->
<dependency>
  <groupId>com.algolia</groupId>
  <artifactId>algoliasearch</artifactId>
</dependency>

Gradle

Update your build.gradle file:
build.gradle
// version 3
implementation 'com.algolia:algoliasearch-core:VERSION'
implementation 'com.algolia:algoliasearch-apache:VERSION'

// version 4
implementation 'com.algolia:algoliasearch:VERSION'
Find the latest version on Maven Central.

Update imports

The package structure changed. Client classes moved from com.algolia.search to com.algolia.api, and model classes moved to com.algolia.model.search.
Java
// version 3
import com.algolia.search.DefaultSearchClient;
import com.algolia.search.SearchClient;
import com.algolia.search.SearchIndex;
import com.algolia.search.models.indexing.Query;
import com.algolia.search.models.indexing.SearchResult;

// version 4
import com.algolia.api.SearchClient;
import com.algolia.model.search.*;
Version 4 also includes dedicated client classes for each API:
Java
// Search API
import com.algolia.api.SearchClient;
// Recommend API
import com.algolia.api.RecommendClient;
// A/B testing API
import com.algolia.api.AbtestingClient;
// Analytics API
import com.algolia.api.AnalyticsClient;
// Personalization API
import com.algolia.api.PersonalizationClient;
// Query Suggestions API
import com.algolia.api.QuerySuggestionsClient;

Update client initialization

In version 3, the DefaultSearchClient.create() factory method created the client. Version 4 removes this factory. Use the SearchClient constructor instead.
Java
// version 3
SearchClient client = DefaultSearchClient.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");

// version 4
var client = new SearchClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");
The version 4 client implements Closeable. Use try-with-resources to ensure the client is properly closed:
Java
// version 4 (recommended)
try (var client = new SearchClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")) {
    // use client
}

Understand the new API surface

Version 4 introduces two major changes to the API surface:
  • No more initIndex. In version 3, the client created a typed SearchIndex<T> object with methods called on it. In version 4, the SearchIndex class is gone. All methods belong to the client instance, with indexName as a parameter.
  • Generic type parameter moves to each method call. In version 3, you set the result type once on initIndex("INDEX", Record.class). In version 4, you pass the target class (for example, Hit.class) as the last argument to each method that returns typed results, such as searchSingleIndex or getObject.
Java
// version 3
SearchClient client = DefaultSearchClient.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.search(new Query("QUERY"));

// version 4
var client = new SearchClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");
client.searchSingleIndex(
    "INDEX_NAME",
    new SearchParamsObject().setQuery("QUERY"),
    Hit.class
);
If you have many files to update, search your codebase for initIndex or .initIndex( to find every place that needs changing.

Update search calls

Search a single index

The index.search() method is now client.searchSingleIndex(). Pass the index name, a SearchParamsObject, and the target class:
Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
SearchResult<Record> results = index.search(new Query("QUERY"));

// version 4
var results = client.searchSingleIndex(
    "INDEX_NAME",
    new SearchParamsObject().setQuery("QUERY"),
    Hit.class
);

Search multiple indices

The client.multipleQueries() method is now client.search(). Each request in the list requires an indexName:
Java
// version 3
client.multipleQueries(Arrays.asList(
    new IndexQuery("INDEX_1", new Query("QUERY")),
    new IndexQuery("INDEX_2", new Query("QUERY"))
));

// version 4
var results = client.search(
    new SearchMethodParams().setRequests(Arrays.asList(
        new SearchForHits().setIndexName("INDEX_1").setQuery("QUERY"),
        new SearchForHits().setIndexName("INDEX_2").setQuery("QUERY")
    )),
    Hit.class
);

Search for facet values

The index.searchForFacetValues() method becomes client.searchForFacetValues() with an indexName parameter:
Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.searchForFacetValues("category", "book", new Query());

// version 4
var results = client.searchForFacetValues(
    "INDEX_NAME",
    "category",
    new SearchForFacetValuesRequest().setFacetQuery("book")
);

Update indexing operations

In version 4, indexing methods are on the client instead of the index object, with indexName as a parameter.

Add or replace records

Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.saveObject(record);
index.saveObjects(records);

// version 4
client.saveObject("INDEX_NAME", record);
// saveObjects works the same way:
client.saveObjects("INDEX_NAME", records);

Partially update records

Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.partialUpdateObject(new Record().setObjectID("1").setName("Updated"));

// version 4
client.partialUpdateObject(
    "INDEX_NAME",
    "1",
    Map.of("name", "Updated")
);

Delete records

Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.deleteObject("1");

// version 4
client.deleteObject("INDEX_NAME", "1");

Update settings, synonyms, and rules

Get and set settings

Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
IndexSettings settings = index.getSettings();
index.setSettings(new IndexSettings().setSearchableAttributes(Arrays.asList("title", "author")));

// version 4
IndexSettings settings = client.getSettings("INDEX_NAME");
client.setSettings(
    "INDEX_NAME",
    new IndexSettings().setSearchableAttributes(Arrays.asList("title", "author"))
);

Save synonyms and rules

Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.saveSynonyms(synonymsList);
index.saveRules(rulesList);

// version 4
client.saveSynonyms("INDEX_NAME", synonymsList);
client.saveRules("INDEX_NAME", rulesList);
In version 3, index.replaceAllRules() and index.replaceAllSynonyms() replaced all rules or synonyms. In version 4, use client.saveRules() or client.saveSynonyms() with the clearExistingRules or clearExistingSynonyms parameter set to true.

Update index management

The copyIndex, moveIndex, copyRules, copySynonyms, and copySettings methods are all replaced by a single operationIndex method.

Copy an index

Java
// version 3
client.copyIndex("SOURCE_INDEX_NAME", "DESTINATION_INDEX_NAME");

// version 4
client.operationIndex(
    "SOURCE_INDEX_NAME",
    new OperationIndexParams().setOperation(OperationType.COPY).setDestination("DESTINATION_INDEX_NAME")
);

Move (rename) an index

Java
// version 3
client.moveIndex("SOURCE_INDEX_NAME", "DESTINATION_INDEX_NAME");

// version 4
client.operationIndex(
    "SOURCE_INDEX_NAME",
    new OperationIndexParams().setOperation(OperationType.MOVE).setDestination("DESTINATION_INDEX_NAME")
);

Copy only rules or settings

In version 4, use the scope parameter to limit the operation to specific data:
Java
// version 4: copy only rules and settings from one index to another
client.operationIndex(
    "SOURCE_INDEX_NAME",
    new OperationIndexParams()
        .setOperation(OperationType.COPY)
        .setDestination("DESTINATION_INDEX_NAME")
        .setScope(Arrays.asList(ScopeType.RULES, ScopeType.SETTINGS))
);

Check if an index exists

In version 3, you could check if an index existed using the exists method on the index object. In version 4, use the indexExists helper method on the client:
Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.exists();

// version 4
client.indexExists("INDEX_NAME");

Update task handling

Version 3 supported chaining .waitTask() on operations. Version 4 replaces this pattern with dedicated wait helpers.
Java
// version 3
SearchIndex<Record> index = client.initIndex("INDEX_NAME", Record.class);
index.saveObject(record).waitTask();

// version 4
var response = client.saveObject("INDEX_NAME", record);
client.waitForTask("INDEX_NAME", response.getTaskID());
Version 4 includes three wait helpers:

Helper method changes

The following sections document breaking changes in helper method signatures and behavior between version 3 and version 4.

replaceAllObjects

The safe parameter has been removed. In version 3, passing safe = true caused the helper to wait after each step. In version 4, the helper always waits—equivalent to the previous safe = true behavior. The scopes parameter is now required and must be passed explicitly.
Java
// version 3
index.replaceAllObjects(objects, true);

// version 4
client.replaceAllObjects(
  new ReplaceAllObjectsParams()
    .setIndexName("INDEX_NAME")
    .setObjects(objects)
    .setScopes(Arrays.asList(ScopeType.SETTINGS, ScopeType.RULES, ScopeType.SYNONYMS))
);

saveObjects

The autoGenerateObjectID parameter has been removed. In version 4, every object must include an objectID. To have the API generate object IDs, use chunkedBatch with Action.ADD_OBJECT. Two new optional parameters are available:
  • waitForTasks (default false)
  • batchSize (default 1,000)
Java
// version 3
index.saveObjects(objects, true);

// version 4
// Objects must include objectID, or use chunkedBatch with Action.ADD_OBJECT
client.saveObjects("INDEX_NAME", objects);

// With wait:
client.saveObjects("INDEX_NAME", objects, true);

deleteObjects

Two new optional parameters are available:
  • waitForTasks (default false)
  • batchSize (default 1,000)
Java
// version 3
index.deleteObjects(Arrays.asList("id1", "id2"));

// version 4
client.deleteObjects("INDEX_NAME", Arrays.asList("id1", "id2"));

// With wait:
client.deleteObjects("INDEX_NAME", Arrays.asList("id1", "id2"), true);

partialUpdateObjects

The createIfNotExists parameter is now required—the overload without it has been removed (it previously defaulted to false).
Java
// version 3
// createIfNotExists defaulted to false when omitted
index.partialUpdateObjects(objects);
index.partialUpdateObjects(objects, true);

// version 4
// createIfNotExists is now required
client.partialUpdateObjects("INDEX_NAME", objects, true);

browseObjects, browseRules, browseSynonyms

These helpers no longer return iterable types (IndexIterable, RulesIterable, SynonymsIterable). In version 4, they accept an aggregator callback invoked with each page of results.
Java
// version 3
for (MyObject obj : index.browseObjects(new BrowseIndexQuery("query"))) {
    process(obj);
}

// version 4
List<Object> objects = new ArrayList<>();
client.browseObjects(
  "INDEX_NAME",
  new BrowseParamsObject(),
  MyObject.class,
  response -> objects.addAll(response.getHits())
);

waitForTask

The helper was renamed from waitTask to waitForTask. It now returns GetTaskResponse instead of void, and the timeToWait millisecond parameter is replaced by maxRetries (default 50) and a timeout function (default: exponential backoff capped at 5 seconds).
Java
// version 3
// Returns void; flat timeToWait in milliseconds
index.waitTask(taskId, 100L);

// version 4
// Returns GetTaskResponse; exponential backoff by default
GetTaskResponse response = client.waitForTask("INDEX_NAME", taskId);

// With explicit retry controls:
client.waitForTask("INDEX_NAME", taskId, 50,
    retries -> Math.min(retries * 200, 5000));

waitForAppTask

This is a new helper in version 4.
Java
GetTaskResponse response = client.waitForAppTask(taskId);

waitForApiKey

This is a new standalone helper in version 4.
Java
// Wait for a key to be created:
client.waitForApiKey("my-api-key", ApiKeyOperation.ADD);

// Wait for a key update (pass the expected final state):
client.waitForApiKey("my-api-key", ApiKeyOperation.UPDATE,
    new ApiKey().setAcl(Arrays.asList(Acl.SEARCH)));

generateSecuredApiKey

The method was renamed from generateSecuredAPIKey to generateSecuredApiKey (camelCase normalization). The parameter type also changed from SecuredApiKeyRestriction (singular) to SecuredApiKeyRestrictions (plural).
Java
// version 3
String key = client.generateSecuredAPIKey("parentApiKey",
    new SecuredApiKeyRestriction().setValidUntil(1893456000L));

// version 4
String key = client.generateSecuredApiKey("parentApiKey",
    new SecuredApiKeyRestrictions().setValidUntil(1893456000L));

getSecuredApiKeyRemainingValidity

The parameter was renamed from securedAPIKey to securedApiKey (camelCase normalization).
Java
// version 3
Duration remaining = client.getSecuredApiKeyRemainingValidity(securedAPIKey);

// version 4
Duration remaining = client.getSecuredApiKeyRemainingValidity(securedApiKey);

indexExists

This helper is new in version 4.
Java
boolean exists = client.indexExists("INDEX_NAME");

chunkedBatch

chunkedBatch is now a public helper. In version 3, chunking was an internal detail of saveObjects.
Java
List<BatchResponse> responses = client.chunkedBatch(
    "INDEX_NAME", objects, Action.ADD_OBJECT, true);

copyIndexBetweenApplications

In version 3, the static AccountClient class provided copyIndex and copyIndexAsync for copying an index between two Algolia applications. It accepted two typed SearchIndex<T> objects. In version 4, AccountClient is removed. You can compose existing helpers across two clients to achieve the same result.
Java
// version 3
MultiResponse response = AccountClient.copyIndex(sourceIndex, destinationIndex);

// version 4
SearchClient src = new SearchClient("SRC_APP_ID", "SRC_API_KEY");
SearchClient dst = new SearchClient("DST_APP_ID", "DST_API_KEY");

// Copy settings
IndexSettings settings = src.getSettings("SOURCE_INDEX");
dst.setSettings("DEST_INDEX", settings);

// Copy rules
List<Rule> rules = new ArrayList<>();
src.browseRules("SOURCE_INDEX", Rule.class, r -> rules.addAll(r.getHits()));
if (!rules.isEmpty()) dst.saveRules("DEST_INDEX", rules);

// Copy synonyms
List<SynonymHit> synonyms = new ArrayList<>();
src.browseSynonyms("SOURCE_INDEX", SynonymHit.class, r -> synonyms.addAll(r.getHits()));
if (!synonyms.isEmpty()) dst.saveSynonyms("DEST_INDEX", synonyms);

// Copy objects
List<MyModel> objects = new ArrayList<>();
src.browseObjects("SOURCE_INDEX", MyModel.class, r -> objects.addAll(r.getHits()));
dst.replaceAllObjects("DEST_INDEX", objects);

saveObjectsWithTransformation

New in version 4. Routes objects through the Algolia Push connector. Requires the transformation region to be set at client initialization.
Java
List<WatchResponse> responses = client.saveObjectsWithTransformation(
    "INDEX_NAME", objects, true);

replaceAllObjectsWithTransformation

New in version 4. Atomically replaces all objects via the Push connector (copy settings/rules/synonyms to a temp index → push objects → move back). Requires the transformation region to be set at client initialization.
Java
ReplaceAllObjectsWithTransformationResponse response =
    client.replaceAllObjectsWithTransformation("INDEX_NAME", objects, 1000,
        Arrays.asList(ScopeType.SETTINGS, ScopeType.RULES, ScopeType.SYNONYMS));

partialUpdateObjectsWithTransformation

New in version 4. Routes partial updates through the Push connector. The createIfNotExists parameter defaults to false.
Java
List<WatchResponse> responses =
    client.partialUpdateObjectsWithTransformation(
        "INDEX_NAME", objects, false, false, 1000);

Method changes reference

The following tables list all method names that changed between version 3 and version 4.

Search API client

Version 3 (legacy)Version 4 (current)
client.addApiKeyclient.addApiKey
client.addApiKey.waitclient.waitForApiKey
client.clearDictionaryEntriesclient.batchDictionaryEntries
client.copyIndexclient.operationIndex
client.copyRulesclient.operationIndex
client.copySynonymsclient.operationIndex
client.deleteApiKeyclient.deleteApiKey
client.deleteDictionaryEntriesclient.batchDictionaryEntries
client.generateSecuredApiKeyclient.generateSecuredApiKey
client.getApiKeyclient.getApiKey
client.getSecuredApiKeyRemainingValidityclient.getSecuredApiKeyRemainingValidity
client.listApiKeysclient.listApiKeys
client.listIndicesclient.listIndices
client.moveIndexclient.operationIndex
client.multipleBatchclient.multipleBatch
client.multipleQueriesclient.search
client.replaceDictionaryEntriesclient.batchDictionaryEntries
client.restoreApiKeyclient.restoreApiKey
client.saveDictionaryEntriesclient.batchDictionaryEntries
client.updateApiKeyclient.updateApiKey
index.batchclient.batch
index.browseObjectsclient.browseObjects
index.browseRulesclient.browseRules
index.browseSynonymsclient.browseSynonyms
index.clearObjectsclient.clearObjects
index.clearRulesclient.clearRules
index.clearSynonymsclient.clearSynonyms
index.copySettingsclient.operationIndex
index.deleteclient.deleteIndex
index.deleteByclient.deleteBy
index.deleteObjectclient.deleteObject
index.deleteObjectsclient.deleteObjects
index.deleteRuleclient.deleteRule
index.deleteSynonymclient.deleteSynonym
index.existsclient.indexExists
index.findObjectclient.searchSingleIndex
index.getObjectclient.getObject
index.getObjectsclient.getObjects
index.getRuleclient.getRule
index.getSettingsclient.getSettings
index.getSynonymclient.getSynonym
index.getTaskclient.getTask
index.partialUpdateObjectclient.partialUpdateObject
index.partialUpdateObjectsclient.partialUpdateObjects
index.replaceAllObjectsclient.replaceAllObjects
index.replaceAllRulesclient.saveRules
index.replaceAllSynonymsclient.saveSynonyms
index.saveObjectclient.saveObject
index.saveObjectsclient.saveObjects
index.saveRuleclient.saveRule
index.saveRulesclient.saveRules
index.saveSynonymclient.saveSynonym
index.saveSynonymsclient.saveSynonyms
index.searchclient.searchSingleIndex
index.searchForFacetValuesclient.searchForFacetValues
index.searchRulesclient.searchRules
index.searchSynonymsclient.searchSynonyms
index.setSettingsclient.setSettings
index.{operation}.waitclient.waitForTask

Recommend API client

Version 3 (legacy)Version 4 (current)
client.getFrequentlyBoughtTogetherclient.getRecommendations
client.getRecommendationsclient.getRecommendations
client.getRelatedProductsclient.getRecommendations
Last modified on April 22, 2026