# How to use KV Store with Redis-compatible SDK

import DocButton from '~/components/webkit/DocButton.vue';

The Azion KV SDK provides a Redis-like client interface for interacting with 
KV Store. This makes it easier to migrate existing applications that use Redis 
patterns and provides a familiar developer experience.

<DocButton href="/en/documentation/products/store/kv-store/" label="Go to KV Store reference" kind="secondary" size="medium" />

---

## Requirements

Before you begin, make sure you have:

- An [Azion account](https://console.azion.com/signup).
- A KV Store namespace created via Console or API.
- Node.js 18+ or a compatible JavaScript runtime.

---

## Installing the SDK

Install the Azion SDK using npm:

```bash
npm install azion
```

---

## Creating a client

The SDK uses a Redis-like client pattern with chainable methods:

```typescript
import { createClient } from 'azion/kv';

// Create and connect a client
const client = await createClient()
  .on('error', (err) => console.error('KV Client Error:', err))
  .connect();
```

### Client options

You can customize the client with options:

```typescript
const client = await createClient({
  namespace: 'my-namespace',
  apiToken: 'my-token',
})
  .on('error', (err) => console.error('KV Error:', err))
  .connect();
```

| Option | Type | Description |
|--------|------|-------------|
| `namespace` | string | The KV Store namespace to use |
| `apiToken` | string | Your Azion API token (required for API provider) |

---

## Storing data

Use the `set` method to store values:

```typescript
// Simple set
await client.set('user:123', 'John Doe');

// Set with expiration (10 seconds)
await client.set('session:abc', 'session-data', {
  expiration: {
    type: 'EX',
    value: 10,
  },
});

// Set with metadata
await client.set('config:theme', 'dark', {
  metadata: { 
    updatedBy: 'admin',
    version: 1 
  },
});

// Set with both expiration and metadata
await client.set('cache:api-response', JSON.stringify(data), {
  expiration: {
    type: 'EX',
    value: 300, // 5 minutes
  },
  metadata: { 
    source: 'external-api',
    cached_at: Date.now() 
  },
});
```

### Expiration types

| Type | Description |
|------|-------------|
| `EX` | Expiration time in seconds |
| `PX` | Expiration time in milliseconds |
| `EXAT` | Unix timestamp in seconds |
| `PXAT` | Unix timestamp in milliseconds |

---

## Retrieving data

Use the `get` method to retrieve values:

```typescript
// Simple get
const value = await client.get('user:123');
console.log(value); // 'John Doe'

// Returns null if key doesn't exist
const missing = await client.get('non-existent');
console.log(missing); // null
```

### Retrieving with metadata

Use `getWithMetadata` to get both the value and its metadata:

```typescript
const result = await client.getWithMetadata('config:theme');
console.log(result.value);    // 'dark'
console.log(result.metadata); // { updatedBy: 'admin', version: 1 }
```

---

## Deleting data

Use `delete` or `del` to remove keys:

```typescript
await client.delete('user:123');
// or
await client.del('user:123');
```

---

## Hash operations

The SDK provides Redis-compatible hash operations for working with field-value pairs:

### hSet / HSET

Store a field-value pair:

```typescript
await client.hSet('user:profile:123', 'name', 'John Doe');
await client.hSet('user:profile:123', 'email', 'john@example.com');
await client.hSet('user:profile:123', 'role', 'admin');

// Uppercase alias also available
await client.HSET('user:profile:123', 'status', 'active');
```

### hGetAll / HGETALL

Get all fields and values:

```typescript
const profile = await client.hGetAll('user:profile:123');
console.log(profile);
// { name: 'John Doe', email: 'john@example.com', role: 'admin', status: 'active' }

// Uppercase alias
const data = await client.HGETALL('user:profile:123');
```

### hVals / HVALS

Get all values (without field names):

```typescript
const values = await client.hVals('user:profile:123');
console.log(values);
// ['John Doe', 'john@example.com', 'admin', 'active']

// Uppercase alias
const vals = await client.HVALS('user:profile:123');
```

---

## Provider detection

The SDK automatically detects the runtime environment and selects the appropriate provider:

- **Native provider**: Used when running inside Azion Functions runtime
- **API provider**: Used when running outside Azion (local development, external servers)

You can check which provider is being used:

```typescript
const providerType = client.getProviderType();
console.log(providerType); // 'native' or 'api'
```

---

## Error handling

The SDK uses an event-based error handling pattern:

```typescript
const client = await createClient()
  .on('error', (err) => {
    console.error('KV Error:', err.message);
    // Handle error (retry, fallback, etc.)
  })
  .connect();
```

You can also use try-catch for individual operations:

```typescript
try {
  await client.set('key', 'value');
} catch (error) {
  console.error('Failed to set value:', error);
}
```

---

## Disconnecting

Always disconnect when you're done:

```typescript
await client.disconnect();
// or
await client.quit();
```

---

## Complete example

Here's a complete example showing common operations:

```typescript
import { createClient } from 'azion/kv';

async function main() {
  // Create and connect client
  const client = await createClient({
    namespace: 'my-app',
  })
    .on('error', (err) => console.error('KV Error:', err))
    .connect();

  try {
    // Store user data
    await client.set('user:1', JSON.stringify({ name: 'Alice', age: 30 }), {
      expiration: { type: 'EX', value: 3600 }, // 1 hour
      metadata: { created: Date.now() },
    });

    // Store user profile using hash operations
    await client.hSet('profile:1', 'theme', 'dark');
    await client.hSet('profile:1', 'language', 'en');
    await client.hSet('profile:1', 'notifications', 'true');

    // Retrieve user data
    const userData = await client.get('user:1');
    console.log('User:', JSON.parse(userData));

    // Retrieve with metadata
    const result = await client.getWithMetadata('user:1');
    console.log('Created at:', result.metadata.created);

    // Get all profile settings
    const profile = await client.hGetAll('profile:1');
    console.log('Profile:', profile);

    // Clean up
    await client.delete('user:1');

  } finally {
    await client.disconnect();
  }
}

main().catch(console.error);
```

---

## Redis method mapping

| Redis Command | SDK Method | Description |
|---------------|------------|-------------|
| `GET` | `get(key)` | Get a value |
| `SET` | `set(key, value, options?)` | Set a value |
| `DEL` | `delete(key)` / `del(key)` | Delete a key |
| `HSET` | `hSet(key, field, value)` / `HSET(...)` | Set hash field |
| `HGETALL` | `hGetAll(key)` / `HGETALL(key)` | Get all hash fields |
| `HVALS` | `hVals(key)` / `HVALS(key)` | Get all hash values |

---

## Next steps

- Learn more about [KV Store](/en/documentation/products/store/kv-store/)
- Explore [managing KV Store with Functions](/en/documentation/products/guides/kv-store/manage-with-functions/)