npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

effect-kv

v2.0.0

Published

Lightweight, type-safe wrapper around Cloudflare KV using Effect.ts

Readme

Effect-KV

A lightweight, type-safe wrapper around Cloudflare KV using Effect.ts. This library provides a functional programming interface with ergonomic DX, full type safety, and structured error handling.

Features

  • Full Type Safety: Leverages Effect's powerful type system and Schema validation
  • Functional Programming: Pure functions, immutable operations, and composable effects
  • Structured Errors: Tagged errors for type-safe error handling
  • Schema Validation: Runtime type checking with Effect Schema
  • Testable: Easy mocking with provided test layers
  • Ergonomic DX: Sensible defaults, fluent APIs, and excellent IntelliSense

Installation

npm install effect-kv effect
# or
pnpm add effect-kv effect
# or
yarn add effect-kv effect

Quick Start

Basic Usage

import { Effect } from 'effect';
import { KV, layerFromNamespace } from 'effect-kv';
import type { KVNamespace } from '@cloudflare/workers-types';

// In a Cloudflare Worker
export default {
  async fetch(request, env): Promise<Response> {
    const program = Effect.gen(function* () {
      const kv = yield* KV;

      // Store a value
      yield* kv.put('key', 'value', { expirationTtl: 3600 });

      // Retrieve a value
      const value = yield* kv.get('key');

      // Handle missing values
      if (Option.isNone(value)) {
        return new Response('Not found', { status: 404 });
      }

      return new Response(value.value);
    });

    const result = await Effect.runPromise(
      program.pipe(Effect.provide(layerFromNamespace(env.MY_KV_NAMESPACE)))
    );

    return result;
  },
} satisfies ExportedHandler<{ MY_KV_NAMESPACE: KVNamespace }>;

Type-Safe Operations with Schema Validation

import { Effect, Schema } from 'effect';
import { KV, layerFromNamespace } from 'effect-kv';

const UserSchema = Schema.Struct({
  id: Schema.Number,
  name: Schema.String,
  email: Schema.String.pipe(Schema.pattern(/.+@.+\..+/)),
});

type User = Schema.Schema.Type<typeof UserSchema>;

const program = Effect.gen(function* () {
  // Pass schema to KV for type-safe JSON operations
  const userKV = yield* KV(UserSchema);

  // Type-safe put - validates at runtime
  yield* userKV.put('user:123', {
    id: 123,
    name: 'Alice',
    email: '[email protected]',
  });

  // Type-safe get - returns Option<User>
  const user = yield* userKV.get('user:123');

  // Type-safe getOrFail - returns User or fails
  const existingUser = yield* userKV.getOrFail('user:123');

  return existingUser;
});

Error Handling

import { Effect } from 'effect';
import { KV, KVGetError, KeyNotFoundError } from 'effect-kv';

const program = Effect.gen(function* () {
  const kv = yield* KV;
  const value = yield* kv.getOrFail('might-not-exist');
  return value;
}).pipe(
  // Handle specific error types
  Effect.catchTag('KeyNotFoundError', (error) => Effect.succeed(`Key ${error.key} was not found`)),
  Effect.catchTag('KVGetError', (error) => Effect.succeed(`Error getting value: ${error.message}`))
);

Working with JSON

const program = Effect.gen(function* () {
  const kv = yield* KV;

  // Automatic JSON serialization
  yield* kv.putJSON('config', {
    theme: 'dark',
    notifications: true,
  });

  // Automatic JSON parsing
  const config = yield* kv.getJSON<{ theme: string; notifications: boolean }>('config');

  return config;
});

API Reference

Basic Usage (String Key-Values)

Use yield* KV for default string-based operations:

const kv = yield * KV;

// Store and retrieve strings
yield * kv.put('key', 'value');
const value = yield * kv.get('key'); // Option<string>

KV.get(key, options?)

Retrieves a value as text. Returns Effect<Option<string>, KVGetError>.

KV.getJSON<T>(key, options?)

Retrieves and parses a JSON value. Returns Effect<Option<T>, KVGetError>.

KV.getArrayBuffer(key, options?)

Retrieves a value as ArrayBuffer. Returns Effect<Option<ArrayBuffer>, KVGetError>.

KV.getStream(key, options?)

Retrieves a value as ReadableStream. Returns Effect<Option<ReadableStream>, KVGetError>.

KV.put(key, value, options?)

Stores a value. Returns Effect<void, KVPutError>.

KV.putJSON<T>(key, value, options?)

Serializes and stores JSON. Returns Effect<void, KVPutError>.

KV.delete(key)

Deletes a key. Returns Effect<void, KVDeleteError>.

KV.list(options?)

Lists keys with optional prefix/limit. Returns Effect<ListResult, KVListError>.

Convenience Methods

KV.getOrFail(key, options?)

Gets value or fails with KeyNotFoundError. Returns Effect<string, KVError>.

KV.getOrElse(key, defaultValue, options?)

Gets value or returns default. Returns Effect<string, KVError>.

Schema-Validated JSON Operations

Use yield* KV(Schema) for type-safe JSON operations with runtime validation:

const UserSchema = Schema.Struct({
  id: Schema.Number,
  name: Schema.String,
});

const userKV = yield * KV(UserSchema);

// Store validated user
yield * userKV.put('user:1', { id: 1, name: 'Alice' });

// Retrieve validated user
const user = yield * userKV.get('user:1'); // Option<{ id: number, name: string }>

KV(schema)

Creates a type-safe KV wrapper for the given schema. Returns Effect<TypedKV<V>, never, KV>.

The returned TypedKV<V> has these methods:

  • get(key) - Returns Effect<Option<V>, KVError>
  • put(key, value, options?) - Returns Effect<void, KVError>
  • getOrFail(key) - Returns Effect<V, KVError>
  • getOrElse(key, defaultValue) - Returns Effect<V, KVError>

makeTypedKV(schema)

Alternative to KV(schema). Creates a type-safe KV wrapper. Returns Effect<TypedKV<V>, never, KV>.

Note: makeTypedKV is kept for backwards compatibility. The recommended approach is yield* KV(Schema).

Testing

The library provides test utilities for easy mocking:

import { describe, it, expect } from 'vitest';
import { KV, KVTest } from 'effect-kv';
import { Effect } from 'effect';

// Create a mock KV namespace
const mockKV = {
  get: async () => 'mock-value',
  put: async () => {},
  delete: async () => {},
  list: async () => ({ keys: [], list_complete: true }),
} as unknown as KVNamespace;

describe('My Tests', () => {
  it('should work with mock KV', async () => {
    const program = Effect.gen(function* () {
      const kv = yield* KV;
      yield* kv.put('test', 'value');
      const value = yield* kv.get('test');
      return value;
    });

    const result = await Effect.runPromise(program.pipe(Effect.provide(KVTest(mockKV))));

    expect(result).toEqual(Option.some('mock-value'));
  });
});

Error Types

All errors are tagged for type-safe handling:

  • KVGetError - Failed to retrieve a value
  • KVPutError - Failed to store a value
  • KVDeleteError - Failed to delete a key
  • KVListError - Failed to list keys
  • KeyNotFoundError - Key does not exist (used by getOrFail)

License

MIT