# What Database Does OmniRoute Use and How Is It Configured?

> OmniRoute uses SQLite with better-sqlite3 and WAL journaling. Learn how to configure its database using environment variables like DATA_DIR for efficient data storage.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-31

---

**OmniRoute uses SQLite via the `better-sqlite3` driver with WAL journaling enabled, configured through environment variables like `DATA_DIR` for storage location.**

OmniRoute persists all state—including providers, models, routing combos, API keys, and usage logs—in a single SQLite database. The architecture prioritizes simplicity, reliability, and concurrent access safety through write-ahead logging. Configuration is environment-driven with sensible defaults, making deployment straightforward across local development and containerized production environments.

## Core Database Technology: SQLite with better-sqlite3

OmniRoute relies on SQLite as its sole persistence layer. The native Node addon **`better-sqlite3`** provides synchronous, high-performance access to the database, avoiding the complexity of external database servers.

The database is instantiated as a **singleton** via `getDbInstance()` in [[`src/lib/db/core.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/core.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/src/lib/db/core.ts). This ensures a single connection is reused throughout the application lifecycle, preventing file locking issues and connection pool overhead.

### WAL Mode for Concurrent Access

When the database opens, OmniRoute automatically enables **write-ahead-log (WAL) journaling** with `PRAGMA journal_mode=WAL`. This configuration delivers two critical benefits:

- **Concurrent reads and writes** – Multiple processes can query the database while a single write proceeds through the WAL
- **Crash recovery** – The WAL allows fast, automatic recovery without requiring full database verification

The resulting file layout follows standard SQLite conventions:

```

${DATA_DIR}/storage.sqlite          # main database file

${DATA_DIR}/storage.sqlite-wal      # write-ahead log

${DATA_DIR}/storage.sqlite-shm      # shared-memory index

```

## Environment-Based Configuration

OmniRoute database configuration is controlled through environment variables defined in [[`docs/reference/ENVIRONMENT.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/reference/ENVIRONMENT.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/reference/ENVIRONMENT.md) and [[`docs/ops/DATABASE_GUIDE.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/ops/DATABASE_GUIDE.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/ops/DATABASE_GUIDE.md):

| Variable | Purpose | Default |
|----------|---------|---------|
| **`DATA_DIR`** | Directory containing `storage.sqlite` | `~/.omniroute` (local) or `/app/data` (Docker) |
| **`STORAGE_DRIVER`** | Database driver selection | `sqlite` (fixed, no runtime alternatives) |
| **`OMNIROUTE_SKIP_POSTINSTALL`** | Skip native dependency rebuild | `0` (set to `1` for CI environments) |
| **`OMNIROUTE_BUILDING`** | Build-phase detection | Undefined (sets DB to no-op stub when present) |

### Changing the Storage Location

Relocate the database by overriding `DATA_DIR`:

```bash

# Local development

export DATA_DIR=/var/lib/omniroute
omniroute start

# Docker deployment

docker run -v /host/data:/app/data -e DATA_DIR=/app/data diegosouzapw/omniroute

```

### Build-Time Database Handling

During build processes, setting `OMNIROUTE_BUILDING` prevents the native addon from loading. The [[`src/lib/buildPhase.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/buildPhase.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/src/lib/buildPhase.ts) module returns a no-op stub, allowing Next.js builds and other compilation steps to proceed without database initialization.

## Runtime Fallback Resolver

If the bundled `better-sqlite3` binary fails to load—due to platform incompatibility or missing native dependencies—OmniRoute activates a **runtime resolver** at [`bin/cli/runtime/sqliteRuntime.mjs`](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/bin/cli/runtime/sqliteRuntime.mjs). This resolver attempts two pure-JavaScript alternatives in order:

1. **`node:sqlite`** – Node.js 22.5+ built-in SQLite module (preferred fallback)
2. **`sql-js`** – In-memory SQLite implementation (last-resort fallback)

These alternatives are documented in [[`docs/ops/SQLITE_RUNTIME.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/ops/SQLITE_RUNTIME.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/ops/SQLITE_RUNTIME.md). Performance degrades progressively: `better-sqlite3` offers native speed, `node:sqlite` provides acceptable throughput for moderate loads, and `sql-js` should only be used for development or minimal deployments.

## Working with the Database in Code

### Obtaining the Database Instance

Import the singleton from the core module:

```typescript
import { getDbInstance } from '@/src/lib/db/core';

// Returns the singleton better-sqlite3 Database object
const db = getDbInstance();

```

### Executing Queries

Prepared statements provide optimal performance and SQL injection protection:

```typescript
// Read operation with parameter binding
const rows = db.prepare(`
  SELECT id, name, api_key
  FROM providers
  ORDER BY id
  LIMIT 5
`).all();

console.log(rows);

```

### Transactional Writes

The WAL-enabled database supports atomic transactions with automatic rollback:

```typescript
const insert = db.prepare(`
  INSERT INTO api_keys (key, owner, created_at)
  VALUES (?, ?, datetime('now'))
`);

// Transaction rolls back on any thrown error
db.transaction(() => {
  insert.run('my-secret-key', 'admin');
  insert.run('secondary-key', 'service-account');
})();

```

## Operational Maintenance

### Integrity Verification

Validate database health using the standard SQLite CLI:

```bash
sqlite3 $DATA_DIR/storage.sqlite "PRAGMA integrity_check;"

```

Expected output: `ok`

### Backup and Recovery

Since SQLite stores everything in a single file, standard filesystem tools apply:

```bash

# Hot backup (safe with WAL mode)

cp $DATA_DIR/storage.sqlite $DATA_DIR/backup-$(date +%Y%m%d).sqlite

# Restore

cp backup-20240115.sqlite $DATA_DIR/storage.sqlite

```

### WAL Checkpointing

Long-running deployments should periodically run `PRAGMA wal_checkpoint(TRUNCATE)` to prevent unlimited WAL growth. OmniRoute does not auto-checkpoint; schedule this via cron or application hooks for high-write workloads.

## Key Source Files

| Path | Responsibility |
|------|--------------|
| [[`src/lib/db/core.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/core.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/src/lib/db/core.ts) | Singleton instantiation, WAL configuration, connection utilities |
| [[`docs/reference/ENVIRONMENT.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/reference/ENVIRONMENT.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/reference/ENVIRONMENT.md) | Environment variable reference |
| [[`docs/ops/DATABASE_GUIDE.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/ops/DATABASE_GUIDE.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/ops/DATABASE_GUIDE.md) | OS paths, backup procedures, maintenance |
| [[`docs/ops/SQLITE_RUNTIME.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/ops/SQLITE_RUNTIME.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/ops/SQLITE_RUNTIME.md) | Fallback driver documentation |
| [`bin/cli/runtime/sqliteRuntime.mjs`](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/bin/cli/runtime/sqliteRuntime.mjs) | Runtime driver selection logic |

## Summary

- **SQLite** is OmniRoute's sole database, accessed through the **`better-sqlite3`** native driver
- **WAL journaling** enables safe concurrent reads and writes with automatic crash recovery
- Configuration uses **`DATA_DIR`** for storage location and **`STORAGE_DRIVER`** (fixed to `sqlite`)
- **Runtime fallbacks** to `node:sqlite` (Node 22.5+) and `sql-js` exist for unsupported platforms
- The **`getDbInstance()`** singleton in [`src/lib/db/core.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/core.ts) manages all database access
- File-based storage simplifies backup, migration, and container deployment

## Frequently Asked Questions

### Can OmniRoute use PostgreSQL or MySQL instead of SQLite?

No. According to the source code in [[`docs/reference/ENVIRONMENT.md`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/reference/ENVIRONMENT.md)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/docs/reference/ENVIRONMENT.md), `STORAGE_DRIVER` is fixed to `sqlite` with no runtime selection mechanism. The entire application assumes SQLite semantics and file-based storage.

### How do I run OmniRoute with the database on a network-attached storage?

Set `DATA_DIR` to a mounted path with proper locks support. However, SQLite over network filesystems (NFS, SMB) risks corruption due to locking limitations. For production, prefer local SSD storage or use a single container with persistent volume claims that guarantee POSIX advisory locks.

### What happens if better-sqlite3 fails to install on my platform?

The runtime resolver at `bin/cli/runtime/sqliteRuntime.mjs` automatically attempts `node:sqlite` (Node 22.5+) then `sql-js`. Set `OMNIROUTE_SKIP_POSTINSTALL=1` during `npm install` to bypass native builds in CI, then verify runtime fallback behavior matches your performance requirements.

### Is the database encrypted at rest?

No native encryption is configured by default. The `encryptConnectionFields` helper in [[`src/lib/db/core.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/core.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/src/lib/db/core.ts) handles field-level encryption for sensitive connection data, but the database file itself is unencrypted. Use filesystem-level encryption (LUKS, BitLocker, EBS encryption) for compliance requirements.