Skip to main content

SQLite Store

Perfect for local development and testing with zero configuration.

Installation​

npm install @saga-bus/store-sqlite better-sqlite3

Basic Usage​

import Database from 'better-sqlite3';
import { SqliteSagaStore, createSchema } from '@saga-bus/store-sqlite';

// In-memory for tests
const db = new Database(':memory:');
createSchema(db);

const store = new SqliteSagaStore({ db });

const bus = createBus({
transport,
store,
sagas: [{ definition: orderSaga }],
});

await bus.start();

Configuration​

OptionTypeDefaultDescription
dbDatabaseRequiredbetter-sqlite3 Database instance
tableNamestring'sagas'Table name

Full Configuration Example​

import Database from 'better-sqlite3';
import { SqliteSagaStore, createSchema } from '@saga-bus/store-sqlite';

// Option 1: In-memory (tests)
const db = new Database(':memory:');

// Option 2: File-based (development)
const db = new Database('sagas.db');

// Option 3: With options
const db = new Database('sagas.db', {
verbose: console.log, // Log queries
fileMustExist: false, // Create if not exists
});

// Create schema
createSchema(db);

// Create store
const store = new SqliteSagaStore({
db,
tableName: 'saga_instances',
});

Schema​

Automatic​

import { createSchema } from '@saga-bus/store-sqlite';

createSchema(db);

Manual​

CREATE TABLE IF NOT EXISTS sagas (
saga_name TEXT NOT NULL,
saga_id TEXT NOT NULL,
correlation_id TEXT NOT NULL,
version INTEGER NOT NULL DEFAULT 1,
state TEXT NOT NULL,
is_completed INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (saga_name, saga_id)
);

CREATE INDEX IF NOT EXISTS idx_sagas_correlation
ON sagas (saga_name, correlation_id);

CREATE INDEX IF NOT EXISTS idx_sagas_completed
ON sagas (saga_name, is_completed);

Test Example​

import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import Database from 'better-sqlite3';
import { SqliteSagaStore, createSchema } from '@saga-bus/store-sqlite';
import { InMemoryTransport } from '@saga-bus/transport-inmemory';
import { createBus } from '@saga-bus/core';

describe('OrderSaga', () => {
let db: Database.Database;
let store: SqliteSagaStore;
let transport: InMemoryTransport;

beforeEach(() => {
db = new Database(':memory:');
createSchema(db);
store = new SqliteSagaStore({ db });
transport = new InMemoryTransport();
});

afterEach(() => {
db.close();
});

it('processes order flow', async () => {
const bus = createBus({
transport,
store,
sagas: [{ definition: orderSaga }],
});

await bus.start();
await bus.publish({ type: 'OrderSubmitted', orderId: '123' });
// assertions...
await bus.stop();
});
});

When to Use​

  • Unit tests - Fastest option, no setup needed
  • Integration tests - Real SQL without Docker
  • Local development - Persistent dev database
  • Prototyping - Quick iteration
  • CI/CD - No external dependencies

When NOT to Use​

  • Production deployments
  • Multi-process applications
  • High-concurrency scenarios
  • Distributed systems

Synchronous Operations​

better-sqlite3 is synchronous for performance:

// All operations are synchronous under the hood
// Wrapped in Promise for interface compatibility
const saga = await store.getById('OrderSaga', '123');

WAL Mode​

Enable WAL for better concurrency:

const db = new Database('sagas.db');
db.pragma('journal_mode = WAL');

createSchema(db);
const store = new SqliteSagaStore({ db });

Best Practices​

Use In-Memory for Tests​

// Fastest option for unit tests
const db = new Database(':memory:');

Close Database After Tests​

afterEach(() => {
db.close();
});

Use WAL for Development​

// Better concurrent read performance
db.pragma('journal_mode = WAL');

Limitations​

  • Single-process only
  • No concurrent writes across processes
  • Limited to local file system
  • Not suitable for production

Migration to Production​

When ready for production, switch to a production store:

// Development
import { SqliteSagaStore } from '@saga-bus/store-sqlite';
const store = new SqliteSagaStore({ db });

// Production
import { PostgresSagaStore } from '@saga-bus/store-postgres';
const store = new PostgresSagaStore({ connectionString: process.env.DATABASE_URL });

See Also​