# What Database Does Motrix Use and How Is It Integrated?

> Discover the embedded SQLite database powering Motrix, integrated via better-sqlite3. Learn about its type-safe CRUD, schema migrations, and transaction management.

- Repository: [Dr_rOot/Motrix](https://github.com/agalwood/Motrix)
- Tags: internals
- Published: 2026-08-20

---

**Motrix uses an embedded SQLite database accessed through the `better-sqlite3` Node.js library, wrapped in a TypeScript `MotrixDatabase` class that provides schema migrations, transaction management, and type-safe CRUD operations.**

The open-source download manager [agalwood/Motrix](https://github.com/agalwood/Motrix) persists all user tasks, download instances, and notification history locally using SQLite rather than a client-server database. This architecture eliminates external dependencies while ensuring fast, reliable storage that synchronizes seamlessly with the Electron application's lifecycle.

## Database Engine and Dependencies

At the core of Motrix's persistence layer sits **SQLite**, exposed to the Node.js runtime via the native addon **`better-sqlite3`** (version `^13.0.3`). This dependency is declared in the project's [`package.json`](https://github.com/agalwood/Motrix/blob/main/package.json) and provides synchronous, high-performance access to the embedded database engine.

The library is imported directly into the core database module:

```typescript
import Database from 'better-sqlite3'

```

You can find this import statement in [`src/core/session/motrix-database.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/session/motrix-database.ts) at lines 25-27. Unlike traditional databases that require a separate server process, SQLite operates directly on a local file, making it ideal for a desktop application like Motrix that needs to maintain state across user sessions without external configuration.

## The MotrixDatabase Wrapper Class

Rather than interacting with `better-sqlite3` primitives throughout the application, Motrix centralizes all database logic inside the **`MotrixDatabase`** class defined in [`src/core/session/motrix-database.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/session/motrix-database.ts). This wrapper encapsulates a private `BetterSqlite3.Database` instance and exposes high-level methods for executing queries, managing transactions, and validating data schemas using **Zod**.

Key responsibilities of the `MotrixDatabase` class include:

- **Schema migrations** – Automatically creating and updating tables (`tasks`, `task_instances`, `task_files`, `notifications`) when the application starts.
- **Type safety** – Enforcing runtime validation for row types such as `TaskRow`, `TaskInstanceRow`, and `Notification` before insertion or retrieval.
- **Transaction management** – Grouping multiple write operations into atomic transactions to prevent data corruption during concurrent updates.

The constructor initializes the underlying SQLite connection with error handling for busy states and foreign key constraints:

```typescript
// Simplified conceptual view based on lines 91-93 of motrix-database.ts
this.db = new Database(dbPath, {
  timeout: 5000,
  verbose: process.env.NODE_ENV === 'development' ? console.log : undefined
});

```

## Session Layer Integration

The **`SessionManager`** (located in [`src/core/session/session-manager.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/session/session-manager.ts)) orchestrates the database lifecycle. During application startup, it instantiates a single `MotrixDatabase` instance and loads the persisted task state. This singleton pattern ensures that all modules—task handlers, notification engines, and IPC handlers—share a consistent data source.

The integration follows this sequence:

1. **Initialization** – `SessionManager` creates the database wrapper, passing the user data directory path (e.g., `app.getPath('userData') + '/motrix.db'`).
2. **Restore** – On launch, the manager calls `motrixDb.getAllTasks()` to reload incomplete downloads into memory.
3. **Persistence ticks** – At regular intervals or upon state changes, the manager invokes methods like `saveTasksBatch()` to persist deltas to SQLite.
4. **Cleanup** – Old notification entries and completed task history are pruned via the database wrapper's maintenance methods before the application exits.

## Practical Usage Examples

The following patterns demonstrate how Motrix interacts with its SQLite backend through the `MotrixDatabase` API.

### Initializing the Database

Applications or test suites can instantiate the database with either a file path or in-memory storage:

```typescript
import { MotrixDatabase } from '@core/session/motrix-database';
import path from 'path';
import { app } from 'electron';

const dbPath = path.join(app.getPath('userData'), 'motrix.db');
const motrixDb = new MotrixDatabase(dbPath);
await motrixDb.init(); // Executes migrations and validates schema

```

### Persisting Task Batches

When a user creates or updates downloads, the application batches these changes into a single transaction to ensure consistency across related tables:

```typescript
// tasks: Array<TaskWithInstancesAndFiles>
await motrixDb.saveTasksBatch(tasks);

```

Under the hood, `saveTasksBatch` constructs a prepared statement transaction that upserts rows into the `tasks`, `task_instances`, and `task_files` tables. It employs a content-signature cache to skip rows that haven't changed, optimizing write performance during high-frequency update cycles.

### Querying by Motrix ID

Individual task lookups use indexed queries on the `tasks` table, automatically joining related instances:

```typescript
const task = await motrixDb.getTaskByMotrixId('abc123');
if (task) {
  console.log(`Found task: ${task.task.name}`);
}

```

### Inserting Notifications

The notification system leverages database transactions to maintain data integrity between the `notifications` and `notification_occurrences` tables:

```typescript
await motrixDb.insertNotificationWithLedger({
  sourceKey: 'engine-start',
  taskId: null,
  kind: 'info',
  severity: 'info',
  titleKey: 'engine.started',
  titleParams: null,
  bodyKey: null,
  bodyParams: null,
  createdAt: Date.now(),
});

```

If the insertion violates temporal constraints (detected via `NotificationInsertStaleError`), the transaction rolls back automatically, preventing duplicate or out-of-order notification records.

## Summary

- **Motrix relies on SQLite** integrated via the `better-sqlite3` npm package (`^13.0.3`) declared in [`package.json`](https://github.com/agalwood/Motrix/blob/main/package.json).
- **All database operations** are abstracted through the `MotrixDatabase` class in [`src/core/session/motrix-database.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/session/motrix-database.ts), which handles connections, migrations, and Zod-based schema validation.
- **The `SessionManager`** instantiates this wrapper at startup and coordinates state persistence, ensuring the UI layer remains database-agnostic.
- **Transaction safety** is enforced for batch operations involving tasks, files, and notifications, preventing partial writes during application crashes or power failures.

## Frequently Asked Questions

### What database does Motrix use?

Motrix uses **SQLite** as its embedded database engine, accessed through the Node.js library `better-sqlite3`. This allows the application to store all download tasks, metadata, and notification history in a single local file without requiring a separate database server installation.

### Why does Motrix use SQLite instead of a client-server database?

SQLite is serverless and self-contained, making it ideal for a desktop Electron application like Motrix. It eliminates network latency, simplifies deployment (no separate installation required), and provides ACID compliance for local data persistence while maintaining a small footprint on the user's system.

### How does Motrix handle database schema migrations?

The `MotrixDatabase` class in [`src/core/session/motrix-database.ts`](https://github.com/agalwood/Motrix/blob/main/src/core/session/motrix-database.ts) executes schema migrations automatically during the `init()` call. It checks the current schema version stored in SQLite's `user_version` pragma and runs incremental DDL statements to create new tables or alter existing ones, ensuring compatibility across application updates.

### Where is the Motrix database file stored on disk?

By default, the database file is located in the application's user data directory, resolved via Electron's `app.getPath('userData')` API. The specific filename is `motrix.db`, though this path can be customized through settings defined in [`src/shared/types/settings.ts`](https://github.com/agalwood/Motrix/blob/main/src/shared/types/settings.ts) under the `sqlite3DbPath` configuration key.