# Migrating from classic client

This guide helps you migrate an existing application from the Classic Aerospike client to the Developer SDK.

## Why migrate?

The Developer SDK offers several advantages over the classic client:

-   **Cleaner syntax** — Chainable, fluent APIs reduce boilerplate
-   **AEL queries** — Human-readable filter expressions
-   **Better error handling** — Actionable errors with recovery suggestions
-   **Decoupled configuration** — Separate connection from behavior

## Before you start

1.  Ensure your Aerospike server is compatible (version 6.0+)
2.  The Developer SDK is a **separate package** — it doesn’t replace the classic client
3.  You can run both clients side-by-side during migration

## Conceptual changes

### Connection model

**Classic**: Direct client with embedded configuration

**SDK**: Separate `Cluster` (connection) and `Session` (behavior)

-   [Java Classic](#tab-panel-2998)
-   [Java SDK](#tab-panel-2999)
-   [Python Classic](#tab-panel-3000)
-   [Python SDK](#tab-panel-3001)

```java
// Classic: Everything in one place

AerospikeClient client = new AerospikeClient(

    new ClientPolicy(),

    new Host("localhost", 3000)

);
```

```java
import com.aerospike.client.sdk.policy.Behavior;

import com.aerospike.client.sdk.Cluster;

import com.aerospike.client.sdk.ClusterDefinition;

import com.aerospike.client.sdk.Session;

// SDK: Connection separate from behavior

try (Cluster cluster = new ClusterDefinition("localhost", 3000).connect()) {

    Session session = cluster.createSession(Behavior.DEFAULT);

}
```

```python
# Classic: Everything in one place

client = aerospike.client({

    'hosts': [('localhost', 3000)]

}).connect()
```

```python
from aerospike_sdk import Behavior, ClusterDefinition

# SDK: Connection separate from behavior

async with await ClusterDefinition("localhost", 3000).connect() as cluster:

    session = cluster.create_session(Behavior.DEFAULT)
```

### Key and record references

**Classic**: Explicit `Key` objects with namespace, set, and user key

**SDK**: `DataSet` represents namespace + set, `.id()` creates record references

-   [Java Classic](#tab-panel-3002)
-   [Java SDK](#tab-panel-3003)
-   [Python Classic](#tab-panel-3004)
-   [Python SDK](#tab-panel-3005)

```java
Key key = new Key("test", "users", "user-1");
```

```java
DataSet users = DataSet.of("test", "users");

RecordRef ref = users.id("user-1");
```

```python
key = ("test", "users", "user-1")
```

```python
users = DataSet.of("test", "users")

ref = users.id("user-1")
```

## Operation mapping

### Create (put)

-   [Java Classic](#tab-panel-3006)
-   [Java SDK](#tab-panel-3007)
-   [Python Classic](#tab-panel-3008)
-   [Python SDK](#tab-panel-3009)

```java
client.put(null, key, new Bin("name", "Alice"), new Bin("age", 30));
```

```java
session.insert(users)

    .bins("name", "age")

    .id("user-1").values("Alice", 30)

    .execute();
```

```python
client.put(key, {"name": "Alice", "age": 30})
```

```python
await session.insert(key=users.id("user-1")).put(

    {"name": "Alice", "age": 30}

).execute()
```

### Read (get)

-   [Java Classic](#tab-panel-3010)
-   [Java SDK](#tab-panel-3011)
-   [Python Classic](#tab-panel-3012)
-   [Python SDK](#tab-panel-3013)

```java
Record record = client.get(null, key);

String name = record.getString("name");
```

```java
import com.aerospike.client.sdk.Record;

import com.aerospike.client.sdk.RecordStream;

String name;

try (RecordStream stream = session.query(users.id("user-1")).execute()) {

    Record user = stream.getFirstRecord();

    name = user.getString("name");

}
```

```python
key, meta, bins = client.get(key)

name = bins["name"]
```

```python
stream = await session.query(users.id("user-1")).execute()

row = await stream.first_or_raise()

user = row.record_or_raise()

name = user.bins.get("name")

stream.close()
```

### Update

-   [Java Classic](#tab-panel-3014)
-   [Java SDK](#tab-panel-3015)
-   [Python Classic](#tab-panel-3016)
-   [Python SDK](#tab-panel-3017)

```java
client.put(null, key, new Bin("visits", 1), new Bin("updated", true));
```

```java
session.update(users.id("user-1"))

    .bin("visits").setTo(1)

    .bin("updated").setTo(true)

    .execute();
```

```python
client.put(key, {"visits": 1, "updated": True})
```

```python
await (

    session.update(users.id("user-1"))

    .bin("visits").set_to(1)

    .bin("updated").set_to(True)

    .execute()

)
```

### Delete

-   [Java Classic](#tab-panel-3018)
-   [Java SDK](#tab-panel-3019)
-   [Python Classic](#tab-panel-3020)
-   [Python SDK](#tab-panel-3021)

```java
client.delete(null, key);
```

```java
session.delete(users.id("user-1")).execute().close();
```

```python
client.remove(key)
```

```python
stream = await session.delete(key=users.id("user-1")).execute()

stream.close()
```

### Query with filters

-   [Java Classic](#tab-panel-3022)
-   [Java SDK](#tab-panel-3023)
-   [Python Classic](#tab-panel-3024)
-   [Python SDK](#tab-panel-3025)

```java
Statement stmt = new Statement();

stmt.setNamespace("test");

stmt.setSetName("users");

stmt.setFilter(Filter.range("age", 21, 100));

RecordSet rs = client.query(null, stmt);

while (rs.next()) {

    Record record = rs.getRecord();

    // process record

}
```

```java
import com.aerospike.client.sdk.Record;

import com.aerospike.client.sdk.RecordResult;

import com.aerospike.client.sdk.RecordStream;

RecordStream stream = session.query(users)

    .where("$.age >= 21")

    .execute();

stream.forEach((RecordResult result) -> {

    if (result.isOk()) {

        Record row = result.recordOrThrow();

        if (row != null) {

            // process record

        }

    }

});

stream.close();
```

```python
query = client.query("test", "users")

query.where(aerospike.predicates.between("age", 21, 100))

for record in query.results():

    # process record
```

```python
stream = await session.query(users).where("$.age >= 21").execute()

async for row in stream:

    row.record_or_raise()

    pass  # process the returned record

stream.close()
```

## Migration strategy

### Option 1: gradual migration

1.  Add Developer SDK dependency alongside classic
2.  Create new features with Developer SDK
3.  Migrate existing code incrementally
4.  Remove classic client when migration complete

### Option 2: full migration

1.  Create a feature branch
2.  Replace all classic client calls with Developer SDK equivalents
3.  Run comprehensive tests
4.  Deploy with confidence

## What’s not supported (yet)

Some advanced features from the classic client are not yet available in the Developer SDK SDK:

-   Admin operations (cluster management)
-   HyperLogLog
-   GeoJSON queries
-   Some complex expression in the AEL

For these features, continue using the classic client alongside Developer SDK.

## Next steps

-   [Quickstart](https://aerospike.com/docs/develop/client/sdk/quickstart) — Get started with Developer SDK
-   [AEL Queries](https://aerospike.com/docs/develop/client/sdk/concepts/ael) — Learn the query syntax
-   [Error Handling](https://aerospike.com/docs/develop/client/sdk/concepts/errors) — Understand error recovery