slowdep

Wrap any async function with realistic latency.
Test how your app survives slow, unpredictable dependencies.

postgres preset · live samples sampling
$ npm install slowdep

usage

One import. Any async function.

Drop slowdep anywhere you call an external dependency. It preserves the original function signature — same inputs, same outputs, same errors. Just slower and more realistic.

import { withLatency } from 'slowdep';

// your real function, unchanged
const findUser = async (id) => db.query('SELECT * FROM users WHERE id = $1', [id]);

// wrap it — now behaves like real Postgres
const slowFindUser = withLatency(findUser, 'postgres');

const user = await slowFindUser(42); // every call is different
import { withLatency } from 'slowdep';

const slowFetch = withLatency(fetchExternalAPI, {
  p50: 100,         // typical call: ~100ms
  p99: 2000,        // worst 1%: up to 2 seconds
  errorRate: 0.01,  // 1% throw a transient error
});

const data = await slowFetch('/api/users');
import { withLatencyAll } from 'slowdep';

// wrap every method on a client at once
const slowRedis = withLatencyAll(redisClient, 'redis');

await slowRedis.get('key');      // slow
await slowRedis.set('k', 'v');  // slow
await slowRedis.del('key');     // slow

presets

Real-world latency profiles, built in.

Based on real p50/p95/p99 data from production systems. Pass a string and you're done.

presetp50p95p99err rate
'postgres'5ms50ms200ms0.1%
'mysql'4ms40ms180ms0.1%
'redis'1ms5ms20ms0.05%
'mongodb'8ms60ms250ms0.1%
'dynamodb'3ms15ms50ms0.05%
's3'30ms150ms500ms0.1%
'stripe'200ms800ms2000ms0.2%
'openai'800ms3000ms8000ms0.5%
'anthropic'600ms2500ms7000ms0.5%
'http'80ms300ms1000ms1%

how it works

Why setTimeout is lying to you.

A flat delay gives every call the same wait time. Real dependencies don't work like that — they respond in 5ms most of the time, hit 200ms occasionally, and spike past 1s when GC pauses, cold caches, or noisy neighbors show up.

slowdep fits a lognormal distribution to your p50 and p99 values using the Box-Muller transform. The result: fast most of the time, with a realistic long tail — the exact shape that breaks retry logic, timeouts, and circuit breakers in production.

setTimeout(fn, 200)
every call identical.
gives false confidence.
slowdep · lognormal
fast usually. slow sometimes.
rarely very slow. like production.