# Upstash storage

The Upstash storage implementation provides a serverless-friendly storage solution using Upstash's Redis-compatible key-value store.

> **Pricing:** When using Mastra with Upstash, the pay-as-you-go model can result in unexpectedly high costs due to the high volume of Redis commands generated during agent conversations. We strongly recommend using a **fixed pricing plan** for predictable costs. See [Upstash pricing](https://upstash.com/pricing/redis) for details and [GitHub issue #5850](https://github.com/mastra-ai/mastra/issues/5850) for context.

> **Observability Not Supported:** Upstash storage **doesn't support the observability domain**. Traces from the `DefaultExporter` can't be persisted to Upstash, and [Studio's](https://mastra.ai/docs/studio/overview) observability features won't work with Upstash as your only storage provider. To enable observability, use [composite storage](https://mastra.ai/reference/storage/composite) to route observability data to a supported provider like ClickHouse or PostgreSQL.

## Installation

**npm**:

```bash
npm install @mastra/upstash@latest
```

**pnpm**:

```bash
pnpm add @mastra/upstash@latest
```

**Yarn**:

```bash
yarn add @mastra/upstash@latest
```

**Bun**:

```bash
bun add @mastra/upstash@latest
```

## Usage

```typescript
import { UpstashStore } from '@mastra/upstash'

const storage = new UpstashStore({
  id: 'upstash-storage',
  url: process.env.UPSTASH_URL,
  token: process.env.UPSTASH_TOKEN,
})
```

## Parameters

**url** (`string`): Upstash Redis URL

**token** (`string`): Upstash Redis authentication token

**prefix** (`string`): Key prefix for all stored items (Default: `mastra:`)

## Additional notes

### Key Structure

The Upstash storage implementation uses a key-value structure:

- Thread keys: `{prefix}thread:{threadId}`
- Message keys: `{prefix}message:{messageId}`
- Metadata keys: `{prefix}metadata:{entityId}`

### Serverless Benefits

Upstash storage is particularly well-suited for serverless deployments:

- No connection management needed
- Pay-per-request pricing
- Global replication options
- Edge-compatible

### Data Persistence

Upstash provides:

- Automatic data persistence
- Point-in-time recovery
- Cross-region replication options

### Performance Considerations

For optimal performance:

- Use appropriate key prefixes to organize data
- Monitor Redis memory usage
- Consider data expiration policies if needed

## Usage example

### Adding memory to an agent

To add Upstash memory to an agent use the `Memory` class and create a new `storage` key using `UpstashStore` and a new `vector` key using `UpstashVector`. The configuration can point to either a remote service or a local setup.

```typescript
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { UpstashStore } from '@mastra/upstash'

export const upstashAgent = new Agent({
  id: 'upstash-agent',
  name: 'Upstash Agent',
  instructions:
    'You are an AI agent with the ability to automatically recall memories from previous interactions.',
  model: 'openai/gpt-5.4',
  memory: new Memory({
    storage: new UpstashStore({
      id: 'upstash-agent-storage',
      url: process.env.UPSTASH_REDIS_REST_URL!,
      token: process.env.UPSTASH_REDIS_REST_TOKEN!,
    }),
    options: {
      generateTitle: true, // Explicitly enable automatic title generation
    },
  }),
})
```

### Using the agent

Use `memoryOptions` to scope recall for this request. Set `lastMessages: 5` to limit recency-based recall, and use `semanticRecall` to fetch the `topK: 3` most relevant messages, including `messageRange: 2` neighboring messages for context around each match.

```typescript
import 'dotenv/config'

import { mastra } from './mastra'

const threadId = '123'
const resourceId = 'user-456'

const agent = mastra.getAgent('upstashAgent')

const message = await agent.stream('My name is Mastra', {
  memory: {
    thread: threadId,
    resource: resourceId,
  },
})

await message.textStream.pipeTo(new WritableStream())

const stream = await agent.stream("What's my name?", {
  memory: {
    thread: threadId,
    resource: resourceId,
  },
  memoryOptions: {
    lastMessages: 5,
    semanticRecall: {
      topK: 3,
      messageRange: 2,
    },
  },
})

for await (const chunk of stream.textStream) {
  process.stdout.write(chunk)
}
```