Skip to content

KV Stores

KV (Key-Value) stores hold the metadata about your uploads - things like file names, sizes, upload progress, and processing status. While Data Stores hold the actual file content, KV stores hold the information about those files.

Think of it like a library catalog: the books are stored on shelves (data stores), but the catalog (KV store) tells you which book is where, who checked it out, and when it’s due back.

StoreBest ForNot Recommended For
MemoryDevelopment, testing, single-process appsProduction, multi-server
RedisProduction apps, multi-server deploymentsServerless/edge functions
IORedisRedis clusters, enterprise setupsSimple deployments
Cloudflare KVEdge deployments, global distributionStrong consistency needs
Cloudflare DOEdge with strong consistencyNon-Cloudflare environments
FilesystemLocal development, persistence without RedisMulti-server production

Quick Decision Guide:

  • Local development? Use Memory (simplest) or Filesystem (persists between restarts)
  • Single production server? Use Redis
  • Multiple servers? Use Redis (shared state)
  • Cloudflare Workers? Use Cloudflare KV or Durable Objects
  • Need strong consistency at the edge? Use Cloudflare Durable Objects
import { memoryKvStore } from "@uploadista/kv-store-memory";
// Use directly - no configuration needed
const kvStore = memoryKvStore;

Data is lost when the process restarts. Perfect for development.

The simplest option - stores everything in memory. Zero configuration required.

Installation:

npm install @uploadista/kv-store-memory

Characteristics:

  • Ultra-fast (nanoseconds)
  • No external dependencies
  • Data lost on restart
  • Single process only

Best for: Development, testing, prototyping

Production-ready distributed storage using Redis. Supports sharing state across multiple server instances.

Installation:

npm install @uploadista/kv-store-redis @redis/client

Configuration:

import { redisKvStore } from "@uploadista/kv-store-redis";
import { createClient } from "@redis/client";
// Basic connection
const redis = createClient({
url: "redis://localhost:6379",
});
// With authentication
const redis = createClient({
url: "redis://localhost:6379",
password: process.env.REDIS_PASSWORD,
});
// With TLS (for cloud Redis)
const redis = createClient({
url: "rediss://your-redis-host:6380",
password: process.env.REDIS_PASSWORD,
});
await redis.connect();
const kvStore = redisKvStore({ redis });

Characteristics:

  • Sub-millisecond latency
  • Shared across multiple servers
  • Optional persistence (RDB/AOF)
  • Supports clustering for high availability

Best for: Production deployments, multi-server setups

Alternative Redis client with built-in cluster and sentinel support. Use this if you need advanced Redis features.

Installation:

npm install @uploadista/kv-store-ioredis ioredis

Basic configuration:

import { ioredisKvStore } from "@uploadista/kv-store-ioredis";
import Redis from "ioredis";
const redis = new Redis({
host: "localhost",
port: 6379,
password: process.env.REDIS_PASSWORD,
});
const kvStore = ioredisKvStore({ redis });

Cluster configuration:

import Redis from "ioredis";
const cluster = new Redis.Cluster([
{ host: "node1", port: 6379 },
{ host: "node2", port: 6379 },
{ host: "node3", port: 6379 },
]);
const kvStore = ioredisKvStore({ redis: cluster });

Best for: Redis clusters, Sentinel setups, enterprise deployments

Edge-distributed key-value storage for Cloudflare Workers. Data is replicated globally for fast reads.

Installation:

npm install @uploadista/kv-store-cloudflare-kv

Configuration:

import { cloudflareKvStore } from "@uploadista/kv-store-cloudflare-kv";
// Inside your Cloudflare Worker
export default {
async fetch(request, env) {
const kvStore = cloudflareKvStore({ kv: env.UPLOADISTA_KV });
// Use kvStore with Uploadista
},
};

wrangler.toml:

[[kv_namespaces]]
binding = "UPLOADISTA_KV"
id = "abc123"

Characteristics:

  • Global edge distribution
  • Fast reads (< 10ms worldwide)
  • Eventually consistent (writes take ~60 seconds to propagate)
  • Cloudflare Workers only

Best for: Global edge deployments where eventual consistency is acceptable

Strongly consistent edge storage with state isolation. Each upload gets its own Durable Object.

Installation:

npm install @uploadista/kv-store-cloudflare-do

Configuration:

import { durableObjectKvStore } from "@uploadista/kv-store-cloudflare-do";
// Inside your Durable Object
export class UploadDO {
constructor(state, env) {
this.state = state;
}
async fetch(request) {
const kvStore = durableObjectKvStore({ storage: this.state.storage });
// Use kvStore with Uploadista
}
}

Characteristics:

  • Strong consistency
  • Per-object isolation
  • Automatic scaling
  • Cloudflare Workers only

Best for: Edge deployments requiring strong consistency

File-based storage for local development with persistence. Each key is stored as a file.

Installation:

npm install @uploadista/kv-store-filesystem

Configuration:

import { fileKvStore } from "@uploadista/kv-store-filesystem";
const kvStore = fileKvStore({
directory: "./data/kv-store",
});

Characteristics:

  • Data persists between restarts
  • No external dependencies
  • Slower than memory/Redis
  • Single server only

Best for: Local development when you want data to persist

Use different stores for different environments:

import { memoryKvStore } from "@uploadista/kv-store-memory";
import { redisKvStore } from "@uploadista/kv-store-redis";
import { createClient } from "@redis/client";
let kvStore;
if (process.env.NODE_ENV === "production") {
const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();
kvStore = redisKvStore({ redis });
} else {
kvStore = memoryKvStore;
}

KV stores are passed to the Uploadista server during setup:

import { createUploadistaServer } from "@uploadista/server";
import { redisKvStore } from "@uploadista/kv-store-redis";
import { s3Store } from "@uploadista/data-store-s3";
const uploadista = await createUploadistaServer({
kvStore: redisKvStore({ redis }),
dataStore: s3Store({ /* ... */ }),
// ... other options
});

For production deployments that need high availability:

import Redis from "ioredis";
import { ioredisKvStore } from "@uploadista/kv-store-ioredis";
const cluster = new Redis.Cluster([
{ host: "redis-1.example.com", port: 6379 },
{ host: "redis-2.example.com", port: 6379 },
{ host: "redis-3.example.com", port: 6379 },
], {
redisOptions: {
password: process.env.REDIS_PASSWORD,
},
});
const kvStore = ioredisKvStore({ redis: cluster });
  • Verify Redis is running: redis-cli ping should return PONG
  • Check the hostname and port are correct
  • If using Docker, ensure the container is on the same network
  • Memory store: This is expected - use Filesystem or Redis for persistence
  • Redis without persistence: Enable RDB or AOF in Redis configuration
  • Cloudflare KV: Data should persist - check your namespace binding

Cloudflare KV is optimized for read-heavy workloads. If you’re doing many writes:

  • Consider Durable Objects for write-heavy scenarios
  • Writes can take up to 60 seconds to propagate globally
  • Set a maxmemory limit in Redis configuration
  • Configure an eviction policy (e.g., maxmemory-policy allkeys-lru)
  • Ensure old upload metadata is being cleaned up