Thin database orchestration library for Node.js - manage multiple connections with health monitoring and failover
npm install omni-db

> Thin database orchestration library for Node.js ā manage multiple connections with health monitoring and failover.





- š Multi-Database Support ā Bring your own clients (Prisma, Drizzle, Redis, MongoDB, etc.)
- š„ Health Monitoring ā Configurable periodic health checks with timeouts
- š Automatic Failover ā Route to backups when primary is unhealthy
- š” Event System ā Subscribe to connection, health, and failover events
- š¦ Minimal Footprint ā Zero runtime dependencies, <10KB bundle
- š· TypeScript Ready ā Full type definitions with generics
ā Without OmniDB ā 80+ lines of boilerplate
``javascript
// DIY: Managing multiple databases with health checks and failover
const primaryPool = new Pool({ connectionString: PRIMARY_URL });
const replicaPool = new Pool({ connectionString: REPLICA_URL });
const redis = createClient({ url: REDIS_URL });
let primaryHealthy = true;
let replicaHealthy = true;
let redisHealthy = true;
// Manual health check loop
setInterval(async () => {
try {
await primaryPool.query('SELECT 1');
primaryHealthy = true;
} catch {
primaryHealthy = false;
console.log('[HEALTH] Primary unhealthy');
}
try {
await replicaPool.query('SELECT 1');
replicaHealthy = true;
} catch {
replicaHealthy = false;
}
try {
await redis.ping();
redisHealthy = true;
} catch {
redisHealthy = false;
}
}, 30000);
// Manual failover logic
function getDatabase() {
if (primaryHealthy) return primaryPool;
if (replicaHealthy) {
console.log('[FAILOVER] Using replica');
return replicaPool;
}
throw new Error('All databases unavailable');
}
// Manual graceful shutdown
process.on('SIGTERM', async () => {
clearInterval(healthCheckInterval);
await Promise.all([
primaryPool.end(),
replicaPool.end(),
redis.quit(),
]);
process.exit(0);
});
// Usage
app.get('/users', async (req, res) => {
const db = getDatabase();
const { rows } = await db.query('SELECT * FROM users');
res.json(rows);
});
`
ā
With OmniDB ā 20 lines, zero boilerplate
`javascript
import { Orchestrator } from 'omni-db';
const db = new Orchestrator({
connections: { primary: primaryPool, replica: replicaPool, cache: redis },
failover: { primary: 'replica' },
healthCheck: {
interval: '30s',
checks: {
primary: async (c) => { await c.query('SELECT 1'); return true; },
replica: async (c) => { await c.query('SELECT 1'); return true; },
cache: async (c) => (await c.ping()) === 'PONG',
},
},
});
await db.connect();
db.shutdownOnSignal();
// Usage ā identical, but with automatic failover
app.get('/users', async (req, res) => {
const pg = db.get('primary'); // Auto-routes to replica if primary is down
const { rows } = await pg.query('SELECT * FROM users');
res.json(rows);
});
`
What you get: Health monitoring, automatic failover, event system, graceful shutdown, TypeScript types ā all in <10KB with zero dependencies.
`bash`
npm install omni-db
`javascript
import { Orchestrator } from 'omni-db';
const db = new Orchestrator({
connections: {
primary: prismaClient,
replica: replicaClient,
cache: redisClient,
},
failover: { primary: 'replica' },
healthCheck: {
interval: '30s',
timeout: '5s',
checks: {
primary: async (client) => {
await client.$queryRawSELECT 1;
return true;
},
cache: async (client) => {
const pong = await client.ping();
return pong === 'PONG';
},
},
},
});
// Connect and start health monitoring
await db.connect();
// Get clients (auto-routes to replica if primary is unhealthy)
const client = db.get('primary');
// Check health status
console.log(db.health());
// { primary: { status: 'healthy' }, replica: { status: 'healthy' }, cache: { status: 'healthy' } }
// Disconnect when done
await db.disconnect();
`
Creates a new orchestrator instance.
| Option | Type | Description |
|--------|------|-------------|
| connections | Record | Named database client instances |failover
| | Record | Map primary ā backup names |healthCheck.interval
| | string | Check interval (e.g., '30s', '1m') |healthCheck.timeout
| | string | Timeout per check |healthCheck.retry.retries
| | number | Failed attempts before marking unhealthy |healthCheck.retry.delay
| | string | Waiting time between retries |healthCheck.checks
| | Record | Custom health check functions |circuitBreaker.threshold
| | number | Failures before opening circuit (default: 5) |circuitBreaker.resetTimeout
| | string | Time before half-open (default: '30s') |circuitBreaker.use
| | object | External circuit breaker (opossum, cockatiel) |
| Method | Returns | Description |
|--------|---------|-------------|
| connect() | Promise | Connect and start health monitoring |disconnect()
| | Promise | Disconnect and stop monitoring |get(name)
| | T | Get client (with failover routing) |execute(name, fn)
| | Promise | Execute with automatic circuit breaker |getStats()
| | Record | Get health + circuit breaker stats |list()
| | string[] | Get all connection names |has(name)
| | boolean | Check if connection exists |health()
| | Record | Get health status |recordSuccess(name)
| | void | Record success for circuit breaker |recordFailure(name)
| | void | Record failure for circuit breaker |shutdownOnSignal(opts?)
| | () => void | Register graceful shutdown handlers |isConnected
| | boolean | Connection state |size
| | number | Number of connections |
`javascript${name} connected
db.on('connected', ({ name }) => console.log());${name} disconnected
db.on('disconnected', ({ name }) => console.log());${name}: ${previous} ā ${current}
db.on('health:changed', ({ name, previous, current }) => {
console.log();Switched from ${primary} to ${backup}
});
db.on('failover', ({ primary, backup }) => {
console.log();Recovered ${primary}, was using ${backup}
});
db.on('recovery', ({ primary, backup }) => {
console.log();`
});
Full type inference with generic connections:
`typescript
import { Orchestrator } from 'omni-db';
import { PrismaClient } from '@prisma/client';
import { Redis } from 'ioredis';
const db = new Orchestrator({
connections: {
postgres: new PrismaClient(),
redis: new Redis(),
},
});
const prisma = db.get('postgres'); // Type: PrismaClient
const redis = db.get('redis'); // Type: Redis
``
For detailed guides, see the docs/ folder:
| Guide | Description |
|-------|-------------|
| Getting Started | Installation and basic usage |
| Configuration | All configuration options |
| Architecture | How components work together |
| Health Monitoring | Health checks and status |
| Failover | Automatic failover routing |
| Circuit Breaker | Prevent cascading failures |
| Events | Event system reference |
| Observability | Prometheus, logging, metrics |
| Middleware | Express, Fastify, Koa, Hono, NestJS |
| TypeScript | Type definitions and generics |
| Examples | Real-world usage patterns |
| Best Practices | Patterns, anti-patterns, and tips |
| Error Reference | All errors with causes and solutions |
OmniDB is a thin orchestration layer. It doesn't abstract your databases ā it orchestrates them.
You bring:
- Your database clients (Prisma, Drizzle, pg, Redis, MongoDB...)
- Your health check logic
- Your routing decisions
OmniDB provides:
- Connection registry with O(1) lookup
- Periodic health monitoring
- Automatic failover routing
- Event-driven notifications
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
MIT Ā© Sathvik C