How OmniRoute Uses SQLite with 95 Domain Modules for Persistence
OmniRoute persists all runtime state in a single SQLite file accessed through a singleton database instance, with 95 domain-specific modules each owning their own tables and CRUD operations.
OmniRoute is an open-source LLM routing platform that relies on SQLite for durable storage. The persistence architecture centers on a singleton database instance defined in src/lib/db/core.ts and shared across 95 specialized domain modules. Each module manages its own table schema while leveraging common infrastructure for migrations, encryption, and health monitoring.
The Singleton Database Pattern
The core of OmniRoute's SQLite persistence lives in src/lib/db/core.ts. This module exports getDbInstance(), a factory function that maintains a module-level singleton surviving Next.js hot-module-replacement.
Initialization Sequence
When first called, getDbInstance() executes five critical steps:
- Singleton retrieval — Returns an existing database handle or instantiates a new one
- Data-directory preparation — Ensures
DATA_DIRexists for thestorage.sqlitefile - Schema creation — Runs embedded
SCHEMA_SQLwithCREATE TABLE IF NOT EXISTSstatements for all domain tables - Migration runner — Applies versioned migrations from
db/migrations/without data loss - Optimization & health checks — Configures WAL mode, busy timeout, cache size, and schedules
runDbHealthCheck
// Direct singleton access for low-level operations
import { getDbInstance } from '@/lib/db/core';
function rawQueryExample() {
const db = getDbInstance();
const row = db.prepare('SELECT COUNT(*) as cnt FROM provider_connections').get() as { cnt: number };
console.log('Total connections:', row.cnt);
}
How 95 Domain Modules Share One Database
Each domain module follows a consistent pattern: declare a table, validate operations, and expose typed CRUD helpers. All modules import getDbInstance() from the core, ensuring atomicity across the entire system.
Provider Connections Module
The src/lib/db/providers.ts module demonstrates the pattern. It owns the provider_connections table, encrypts credential fields automatically, and exports functions like getProviderConnections, createProviderConnection, and updateProviderConnection.
import { getProviderConnections, createProviderConnection } from '@/lib/db/providers';
// Retrieve filtered results with column validation
async function listActiveProviders() {
const connections = await getProviderConnections({ isActive: true });
return connections;
}
// Credentials encrypted transparently before storage
async function addConnection() {
await createProviderConnection({
provider: 'openai',
authType: 'apikey',
name: 'My OpenAI Key',
apiKey: 'sk-************',
priority: 10,
isActive: true,
});
}
Other Key Domain Modules
| Module | Table | Responsibility |
|---|---|---|
src/lib/db/combo.ts |
combos |
Routing combo definitions and metadata |
src/lib/db/usageHistory.ts |
Usage records | Per-request tokens, latency, status for analytics |
src/lib/db/callLogs.ts |
Call logs | Request/response artifacts and streaming details |
src/lib/db/quotaSnapshots.ts |
Quota state | Rate-limit enforcement data per connection |
Resilience and Data Protection
The core module provides utilities beyond basic queries. src/lib/db/backup.ts creates managed backups before destructive operations. The system also handles probe-failure recovery, critical-state capture, and graceful degradation to the WASM-based sql.js implementation when the native driver is unavailable.
Summary
- Single-file architecture: All 95 domain modules persist to one
storage.sqlitefile - Singleton pattern:
getDbInstance()insrc/lib/db/core.tsensures consistent, shared database access - Module autonomy: Each domain owns its table schema and CRUD helpers while sharing migration and encryption infrastructure
- Production hardening: WAL mode, health checks, automatic backups, and driver fallback protect data integrity
Frequently Asked Questions
How does OmniRoute prevent data corruption with multiple domain modules writing simultaneously?
The singleton pattern in src/lib/db/core.ts guarantees that all 95 domain modules reference the same Better-SQLite3 instance. SQLite handles concurrency at the file level, and the initialization sets PRAGMA busy_timeout along with WAL mode to mediate concurrent access safely.
What happens if the SQLite schema needs to change in a new release?
The migration runner in getDbInstance() executes versioned SQL files from db/migrations/ on every startup. Each migration runs inside a transaction, evolving tables without destroying existing data. Domain modules remain compatible by using CREATE TABLE IF NOT EXISTS in the base SCHEMA_SQL.
How are sensitive credentials protected in the SQLite database?
The provider connections module (src/lib/db/providers.ts) automatically encrypts fields like apiKey before persisting them. The encryption uses keys derived from environment configuration, ensuring raw credentials never appear in the storage.sqlite file or backup archives.
Can OmniRoute run without a native SQLite driver?
Yes. The core module implements fallback logic that substitutes the WASM-based sql.js implementation when Better-SQLite3 is unavailable. All domain modules continue functioning normally because they interact through the abstracted getDbInstance() interface rather than direct driver calls.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →