# What Database Does FreeLLMAPI Use for Its Ledger? SQLite Implementation Explained

> Discover how FreeLLMAPI uses SQLite for its ledger implementation. Learn about storing rate-limit and usage data with better-sqlite3 and node:sqlite drivers.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: internals
- Published: 2026-09-04

---

**FreeLLMAPI stores its rate-limit and usage ledger in a SQLite database**, using the `better-sqlite3` driver (with a fallback to `node:sqlite` on Android) to persist request counts, token usage, and cooldowns to disk.

FreeLLMAPI is an open-source API gateway that requires robust rate limiting to manage LLM provider quotas. According to the source code in `tashfeenahmed/freellmapi`, the project answers the question "what database does FreeLLMAPI use for its ledger" by implementing a lightweight, file-based SQLite solution that tracks per-key request counts and provider-wide caps without requiring external database servers.

## SQLite as the Ledger Backend

The FreeLLMAPI ledger relies on **SQLite** as its persistent store. The system uses **better-sqlite3** as its primary driver, falling back to the built-in `node:sqlite` module only when running on Android environments. This synchronous, embedded database approach eliminates network overhead while maintaining ACID compliance for rate-limit accounting.

### Default Database Location

By default, FreeLLMAPI creates or opens the SQLite file at `server/data/freeapi.db`. This path is resolved at runtime and passed to the database factory function. Developers can configure alternative paths, but the standard deployment persists all ledger tables—including `rate_limit_usage` and `rate_limit_cooldowns`—within this single file.

### Database Driver Selection

The connection logic in [`server/src/db/index.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/db/index.ts) dynamically selects the appropriate SQLite implementation:

- **Primary driver**: `better-sqlite3` for high-performance synchronous operations
- **Fallback driver**: `node:sqlite` (Node.js built-in) for Android compatibility

## Ledger Schema and Tables

The rate-limit ledger consists of multiple tables defined through migration scripts. The primary table **`rate_limit_usage`** records every request and token consumption event, while **`rate_limit_cooldowns`** tracks provider-specific backoff periods. These tables are created via migration files located in `server/src/db/migrations/`.

## Core Implementation Files

### Recording Usage in ratelimit.ts

The ledger logic resides in [`server/src/services/ratelimit.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/ratelimit.ts), where the `recordRequest()` function persists usage data. This function attempts to write to SQLite first, then falls back to in-memory tracking if the database write fails.

```typescript
// Record a request in the ledger (ratelimit.ts)
export function recordRequest(platform: string, modelId: string, keyId: number) {
  const now = Date.now();
  // Try to persist the request; fall back to in‑memory if DB write fails
  if (!recordUsage(platform, modelId, keyId, 'request', 0, now)) {
    pushMemoryRequest(`${platform}:${modelId}:${keyId}:rpm`, MINUTE, now);
    pushMemoryRequest(`${platform}:${modelId}:${keyId}:rpd`, DAY, now);
  }
}

```

### Connection Management in db/index.ts

Database connection handling is centralized in [`server/src/db/index.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/db/index.ts). The `betterSqliteFactory()` function instantiates the SQLite connection using the resolved file path.

```typescript
// Open the SQLite database (db/index.ts)
function betterSqliteFactory(resolvedPath: string): Db {
  const BetterSqlite = runtimeRequire('better-sqlite3') as new (path: string) => unknown;
  return new BetterSqlite(resolvedPath) as Db;   // ← SQLite connection
}

```

### Migration System

Schema definitions and table creation are handled through the migration CLI in [`server/src/db/migrate/cli.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/db/migrate/cli.ts). Migration files such as [`20260729_000001_custom_model_endpoint_identity.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/20260729_000001_custom_model_endpoint_identity.ts) define the ledger structure, ensuring the `rate_limit_usage` table exists before the server begins recording data.

## How the Ledger Queries Request Counts

When enforcing rate limits, FreeLLMAPI queries the SQLite ledger to determine current usage. The `providerDailyRequestCount()` function demonstrates this pattern by first checking persisted records, then falling back to in-memory counters if necessary.

```typescript
// Retrieve the provider‑wide daily request count (ratelimit.ts)
export function providerDailyRequestCount(platform: string, keyId: number, now = Date.now()): number {
  const windowMs = msSinceUtcMidnight(now);
  const persisted = countPersistedProviderRequests(platform, keyId, windowMs, now);
  if (persisted !== undefined) return persisted;
  // Fallback to in‑memory windows if the DB is unavailable
  // ...
}

```

## Summary

- **FreeLLMAPI uses SQLite** as the persistent backend for its rate-limit ledger, stored by default in `server/data/freeapi.db`.
- The system prefers **better-sqlite3** for synchronous performance, with `node:sqlite` as an Android fallback.
- Ledger tables (`rate_limit_usage`, `rate_limit_cooldowns`) are defined via migrations in `server/src/db/migrations/`.
- Usage recording happens in [`server/src/services/ratelimit.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/ratelimit.ts), with SQL `INSERT` statements tracking per-key requests and token consumption.
- If SQLite writes fail, the system gracefully degrades to in-memory rate limiting to prevent service interruption.

## Frequently Asked Questions

### Does FreeLLMAPI support databases other than SQLite for the ledger?

No. According to the source code in `tashfeenahmed/freellmapi`, the ledger implementation is tightly coupled to SQLite through the `better-sqlite3` and `node:sqlite` drivers. There are no abstraction layers for PostgreSQL, MySQL, or other database engines in the current codebase.

### Where is the FreeLLMAPI ledger database file located?

By default, FreeLLMAPI creates the SQLite database at `server/data/freeapi.db` relative to the project root. This path is resolved and passed to `betterSqliteFactory()` in [`server/src/db/index.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/db/index.ts), though developers can modify the configuration to use alternative locations or in-memory storage (`:memory:`) for testing.

### What happens if the SQLite database becomes unavailable?

FreeLLMAPI implements a graceful degradation strategy. If the SQLite write fails in `recordRequest()`, the system falls back to in-memory tracking via `pushMemoryRequest()`. Similarly, `providerDailyRequestCount()` returns in-memory counts when `countPersistedProviderRequests()` returns undefined, ensuring rate limiting continues even during database outages.

### Which tables store the rate limit data in FreeLLMAPI?

The primary ledger data resides in the **`rate_limit_usage`** table, which records every request and token consumption event with timestamps. The **`rate_limit_cooldowns`** table tracks provider-specific backoff periods. These tables are created and managed through migration scripts in the `server/src/db/migrations/` directory.