Skip to main content
@frontmcp/storage-sqlite provides a local storage backend for FrontMCP using SQLite. It replaces Redis for single-process deployments where you need persistence without managing external infrastructure.

Zero Infrastructure

No Redis or external database needed — just a local file

Persistent Sessions

Sessions, elicitation state, and SSE events survive restarts

Optional Encryption

AES-256-GCM at-rest encryption via HKDF-SHA256

WAL Mode

Write-Ahead Logging enabled by default for better read concurrency

When to Use SQLite

Use CaseSQLiteRedis
Local-only / single-processRecommendedOverkill
Unix socket deploymentsRecommendedNot needed
Background daemonsRecommendedNot needed
Multi-instance productionNot supportedRequired
Pub/Sub (resource subscriptions)EventEmitter (single process)Required for distributed
Edge / serverlessNot supportedRequired
SQLite is ideal for local-only deployments — Unix socket servers, CLI tools, and background daemons. For multi-instance production or serverless, use Redis or Vercel KV instead.

Installation

npm install @frontmcp/storage-sqlite better-sqlite3
# or
yarn add @frontmcp/storage-sqlite better-sqlite3
better-sqlite3 is a native module and requires a C++ compiler. On most systems this is already available. If you run into build issues, see the better-sqlite3 troubleshooting guide.

Quick Start

The simplest way to use SQLite is via the sqlite option on FrontMcpInstance.runUnixSocket():
import { FrontMcpInstance } from '@frontmcp/sdk';
import { serverConfig } from './config';

const handle = await FrontMcpInstance.runUnixSocket({
  ...serverConfig,
  socketPath: '/tmp/my-app.sock',
  sqlite: {
    path: '~/.frontmcp/data/my-app.sqlite',
  },
});
Or via the CLI:
frontmcp socket ./src/main.ts --db ~/.frontmcp/data/my-app.sqlite

With @FrontMcp Decorator

import 'reflect-metadata';
import { FrontMcp } from '@frontmcp/sdk';

@FrontMcp({
  info: { name: 'My Server', version: '1.0.0' },
  http: { port: 3001 },
  sqlite: {
    path: './data/my-app.sqlite',
  },
})
export default class Server {}

Configuration Options

OptionTypeDefaultDescription
pathstringrequiredPath to the .sqlite database file
encryption.secretstringSecret key for AES-256-GCM encryption via HKDF-SHA256
walModebooleantrueEnable WAL mode for better read concurrency
ttlCleanupIntervalMsnumber60000Interval in ms for purging expired keys

Encryption

Enable at-rest encryption to protect stored session data. Keys are stored in plaintext (needed for lookups); only values are encrypted.
sqlite: {
  path: './data/my-app.sqlite',
  encryption: {
    secret: process.env.FRONTMCP_ENCRYPTION_SECRET!,
  },
}
The encryption pipeline:
  1. Your secret is run through HKDF-SHA256 to derive a 256-bit key
  2. Each value is encrypted with AES-256-GCM using a random 96-bit IV
  3. Stored format: base64url(iv):base64url(tag):base64url(ciphertext)
If you lose the encryption secret, stored data becomes unrecoverable. Store the secret securely (environment variable, secrets manager) and keep a backup.

Store Types

@frontmcp/storage-sqlite provides three specialized stores, all built on a common SqliteKvStore:

Session Store

Stores MCP session data with TTL support.
import { SqliteSessionStore } from '@frontmcp/storage-sqlite';

const sessions = new SqliteSessionStore({
  path: './data/app.sqlite',
  keyPrefix: 'mcp:session:',   // default
  defaultTtlMs: 3600000,       // 1 hour (default)
});

await sessions.set('session-123', { user: { sub: 'user-1' } });
const data = await sessions.get('session-123');

Event Store

Stores SSE events for resumability with max event limits and TTL-based eviction.
import { SqliteEventStore } from '@frontmcp/storage-sqlite';

const events = new SqliteEventStore({
  path: './data/app.sqlite',
  maxEvents: 10000,    // default
  ttlMs: 300000,       // 5 minutes (default)
});

const eventId = await events.storeEvent('stream-1', { type: 'update' });

Elicitation Store

Stores pending elicitation requests with EventEmitter-based single-process pub/sub.
import { SqliteElicitationStore } from '@frontmcp/storage-sqlite';

const elicitation = new SqliteElicitationStore({
  path: './data/app.sqlite',
  keyPrefix: 'mcp:elicit:',   // default
});

Comparison: SQLite vs Redis vs Vercel KV

FeatureSQLiteRedisVercel KV
InfrastructureLocal fileServer or managed serviceVercel-managed
Setupnpm installDocker / cloud setupDashboard toggle
Multi-instanceSingle process onlyFull supportFull support
Pub/SubEventEmitter (local)Native Redis pub/subNot supported
EncryptionBuilt-in AES-256-GCMTLS in transitTLS in transit
Edge CompatibleNoNoYes
Latency~0ms (local file I/O)~1-5ms (TCP)~5-15ms (REST)
Best ForLocal daemons, CLI toolsProduction serversVercel deployments

Troubleshooting

Cause: The better-sqlite3 native module is not installed.Solution:
npm install better-sqlite3
If you’re using yarn with PnP, you may need to add it as a dependency (not devDependency).
Cause: The parent directory for the SQLite file doesn’t exist.Solution: Ensure the directory exists before starting the server:
mkdir -p ~/.frontmcp/data
Cause: Multiple processes are trying to write to the same SQLite file simultaneously.Solution: SQLite is designed for single-process access. If you need multiple processes, use Redis instead. WAL mode (enabled by default) helps with read concurrency but doesn’t solve multi-writer scenarios.
Cause: Existing data was encrypted with a different secret.Solution: Either restore the original secret or delete the database file and let the server create a fresh one. There is no migration path between encryption keys.

Unix Socket

Run FrontMCP as a persistent local server over Unix sockets

Redis Setup

Configure Redis for multi-instance production deployments

Vercel KV

Edge-compatible storage for Vercel deployments

Runtime Modes

Compare SDK, Server, and Handler deployment modes