# Reference > Stash

# Stash API

Stash API provides a persistent key-value store for use in your Artillery tests, and offers Redis-compatible features like working with key-value pairs, lists, counters, and more.

This feature is available on all paid plans of Artillery Cloud.

## Features

* Full support for most Redis commands
* Works in all environments where Artillery runs - local, CI, AWS Fargate, AWS Lambda, Azure ACI
* Zero-config -- just pass in your Artillery Cloud API key when running a test
* Globally-distributed with low latency writes & reads

## Use cases

* Making sure that data is only used once in a test by different VUs
* Sharing data between VUs in the same test
* Storing large datasets that get reused between test runs
* Storing arbitrary data generated by VUs for later analysis

## Usage

To use Stash API, run Artillery with `--key` flag to pass in your Artillery Cloud API key. There is no other configuration required to use Stash API.

Artillery will create & configure a Stash API client automatically. The client can be accessed in two ways:

1. The `global.artillery.stash` object in an Artillery test script.
2. By using the `getStash()` function in any Node.js script. This option of accessing a Stash client is useful for various automation scripts, e.g. for pre-seeding a set of data into Stash to be used by test scripts.&#x20;

Stash API is supported by Artillery CLI v2.0.25+. You can check your version of Artillery CLI with:

```sh
artillery version
```

## Examples

### Using Stash API in a virtual user scenario

The following code defines a simple Playwright-based load test. The `helloWorld` function uses the `artillery.stash` object to write data to the Stash database.

```ts {20-25} filename="stash-demo.ts"

export const config = {
  target: 'https://www.artillery.io',
  engines: {
    playwright: {}
  },
  phases: [{
    arrivalCount: 5,
    duration: '10s'
  }]
};

export const scenarios = [{
  engine: 'playwright',
  testFunction: helloWorld
}];

async function helloWorld(page: Page, userContext: any) {
  // Store a unique key/value from this virtual user. $uuid is a
  // built-in variable with a unique id for each VU
  const keyName = `vuId_${userContext.vars.$uuid}`
  await global.artillery.stash.set(, new Date());
  // Set automatic expiry on the key - delete after 10 minutes
  await global.artillery.stash.expire(keyName, 10 * 60);

  await page.goto('https://www.artillery.io/');
  await page.click('text=Docs');
}
```

To make the Stash API available in the test, we have to run it with a valid Artillery Cloud API key:

```sh
artillery run stash-demo.ts --key $ARTILLERY_CLOUD_API_KEY
```

### Using Stash API in an automation script

The following example shows how the Stash API can be used to store data from a CSV file to be used in an Artillery test.

```typescript filename="seed-data.ts"



async function main() {
  // ARTILLERY_CLOUD_API_KEY is required
  if (!process.env.ARTILLERY_CLOUD_API_KEY) {
    throw new Error('ARTILLERY_API_CLOUD_KEY env var must be set');
  }

  // Create a Stash client
  const stash = await getStash();

  // Parse CSV data
  const rows = await parse(fs.readFileSync('data.csv'), 'utf8');

  // Push data from each row into a Redis list under the "csv_data" key
  for (const row of rows) {
    await stash.lpush('csv_data', JSON.stringify(row));
  }
}

main();
```

To run the script use [Node.js v22.18.0](https://nodejs.org/en/learn/typescript/run-natively) or later, or [`tsx`](https://www.npmjs.com/package/tsx).

```sh
# Run with Node.js:
ARTILLERY_CLOUD_API_KEY=a9_yourApiKey node seed-data.ts

# Or run with tsx if using an older release of Node.js:
ARTILLERY_CLOUD_API_KEY=a9_yourApiKey npx tsx seed-data.ts
```

## API

Most Redis commands are supported. The most commonly used ones are listed below.

### Get/set/delete keys

```js
// Set values
await artillery.stash.set('key1', 'val1');
await artillery.stash.set('key2', 'val2');

// Delete keys/values
await artillery.stash.del('key1', 'key2');
```

### Work with keys

```js
// Check if keys named "key1" and "key2" exist
await artillery.stash.exists('key1', 'key2');

// Set expiration time on a key for it to be deleted automatically
// Expire key "key1" after 60 seconds
await artillery.stash.expire('key1', 60)
// Expire key "key1" at a specific time - 24 hours from now
await artillery.stash.expireat('key1', Math.floor(Date.now() / 1000) + 24 * 60 * 60);

// Get a list of all key names
// NOTE: This can take a while for databases with a large number of keys - consider using scan() instead
await artillery.stash.keys();

// Scan the database for keys matching a glob pattern
// Get first batch of results:
const [cursor, keys] = await artillery.stash.scan(
  0,              // initial value for the cursor
  { match: '*' }, // glob for matching key names
  100,            // return up to 100 results each time
);
// Call scan() again with the return value in "cursor" to get more results
const moreKeys = await artillery.stash.scan(cursor, { match: '*' }, 100);
```

### Lists

```js
// Push values to a list
await artillery.stash.lpush('usernames', 'user01', 'user02', 'user03');
// Pop a value atomically from a list
const username = await artillery.stash.lpop('usernames');
// Get length of a list
const length = await artillery.stash.llen('usernames');
```

### Counters

```js
// Increment/decrement counters atomically
const currentCount = await artillery.stash.incr('mycounter');
const newCount = await artillery.stash.decr('mycounter');
```

## Limits

The limits described below are the default limits applied to all Stash databases. If you need to change one of the limits described below please get in touch via [support@artillery.io](mailto:support@artillery.io?subject=Stash%20API).

| Limit    | Value | Notes    |
| -------- | ------- | ------- |
| Database size  | 1 GB    | Total size of data across all keys/values. |
| Commands | 5 million / month | Each operation, such as setting or getting a value counts as one command. |
| Bandwidth | 10 GB / month | Inbound and outbound bandwidth counts towards the limit. |
| Region | `us-east-1` with a read replica in `eu-west-1` | Data is stored in these regions by default. |
| Data retention | Indefinite | Data is not cleaned up automatically, unless TTL is set for specific keys with `stash.expire('key-name', $numberInSeconds)` |

## Security

* Each Stash is created for & isolated to your Artillery Cloud organization.
* One Stash is created for each Artillery Cloud organization, and is accessible by all of its members. We recommend using key name prefixes to help isolate data for different tests or teams.

## FAQ

### What happens if an Artillery Cloud API key is not provided?

When a key is not provided, or does not belong to an organization which has access to Stash API, `global.artillery.stash` will be set to `null`.

### Can default limits be increased?

Yes. Send us an email on [support@artillery.io](mailto:support@artillery.io?subject=Stash%20API) with a description of the limit you'd like to change. There may be extra cost associated with the limit increase.
