Skip to main content

Overview

n8n-MCP uses SQLite to store node documentation, properties, operations, and workflow templates. The database supports two adapters for maximum compatibility across environments.

Database Architecture

Schema Overview

The database contains:
  • nodes table - 1,084 nodes (537 core + 547 community)
  • node_versions table - Version tracking and migration detection
  • templates table - 2,709 workflow templates
  • template_node_configs table - 2,646 pre-extracted configurations
  • workflow_versions table - Rollback and version history
  • FTS5 indexes - Full-text search capabilities

Database Size

  • Typical size: ~70MB (includes templates and community nodes)
  • Location: Configurable via NODE_DB_PATH
  • Format: SQLite 3 with FTS5 extension

Database Adapters

n8n-MCP supports two SQLite adapters with automatic fallback:

better-sqlite3 (Default)

Native C++ bindings for best performance

Performance

Direct disk I/O with native bindings

Memory

~100-120 MB stable usage

Compatibility

Requires compatible Node.js version

Features

Full FTS5, WAL mode, transactions
Characteristics:
  • Direct disk writes (no memory overhead)
  • Fastest query performance (~12ms average)
  • Enabled by default in Docker images (v2.20.2+)
  • Automatic compilation for your Node.js version

sql.js (Fallback)

Pure JavaScript implementation

Compatibility

Works on any Node.js version

Memory

~150-200 MB stable usage

Persistence

Periodic saves to disk

Features

Most SQLite features (no FTS5)
Characteristics:
  • In-memory database with periodic saves
  • Used when better-sqlite3 compilation fails
  • Automatic memory management
  • Configurable save interval

Automatic Adapter Selection

The adapter is selected automatically:
1

Try better-sqlite3

Attempts to load native better-sqlite3
2

Check Compatibility

Verifies Node.js version compatibility
3

Fallback to sql.js

If better-sqlite3 fails, uses sql.js
4

Log Adapter

Logs which adapter is being used
database-adapter.ts
export async function createDatabaseAdapter(dbPath: string): Promise<DatabaseAdapter> {
  try {
    // Try better-sqlite3 first
    const adapter = await createBetterSQLiteAdapter(dbPath);
    logger.info('Successfully initialized better-sqlite3 adapter');
    return adapter;
  } catch (error) {
    // Fall back to sql.js
    logger.warn('Failed to initialize better-sqlite3, falling back to sql.js');
    const adapter = await createSQLJSAdapter(dbPath);
    logger.info('Successfully initialized sql.js adapter');
    return adapter;
  }
}

Configuration

Database Path

NODE_DB_PATH
string
default:"./data/nodes.db"
Path to the SQLite database file. Must end with .db.Examples:
# Local development
NODE_DB_PATH=./data/nodes.db

# Docker
NODE_DB_PATH=/app/data/nodes.db

# Custom location
NODE_DB_PATH=/var/lib/n8n-mcp/nodes.db

Rebuild on Start

REBUILD_ON_START
boolean
default:"false"
Rebuild database on server startup.When to enable:
  • After n8n version upgrades
  • Testing database changes
  • CI/CD environments
REBUILD_ON_START=false
Database rebuilds take 2-3 minutes due to n8n package size. Only enable when necessary.

sql.js Save Interval

SQLJS_SAVE_INTERVAL_MS
number
default:"5000"
Save interval for sql.js adapter (milliseconds).Range: 100-60000ms (1 minute max)Tradeoffs:
  • Lower values = more frequent saves = higher memory churn
  • Higher values = less frequent saves = lower memory usage
# Default (balanced)
SQLJS_SAVE_INTERVAL_MS=5000

# Production (lower memory usage)
SQLJS_SAVE_INTERVAL_MS=10000

Memory Optimization

better-sqlite3 Memory Usage

# Memory usage pattern
Startup:     ~100 MB
Steady-state: ~100-120 MB
Peak:        ~150 MB (during queries)
Optimization tips:
  • Direct disk I/O (no memory buffering)
  • Memory-mapped file I/O
  • Automatic memory management
  • No configuration needed

sql.js Memory Usage

# Memory usage pattern
Startup:     ~150 MB
Steady-state: ~150-200 MB
Save cycle:  +50 MB temporary
Optimization tips:
Reduce save frequency for lower memory churn:
# Recommended for production
SQLJS_SAVE_INTERVAL_MS=10000

Data Loss Considerations

sql.js data loss window: Up to 5 seconds (default) of database changes may be lost if the process crashes before the save timer fires.This is acceptable because:
  • close() saves immediately on graceful shutdown
  • Docker/Kubernetes SIGTERM provides 30s for cleanup
  • MCP server is primarily read-heavy (writes are rare)
  • The alternative (100ms interval) caused 2.2GB memory leaks in production

Database Maintenance

Rebuilding the Database

npm run rebuild

Database Validation

# Validate database integrity
npm run validate

# Test critical nodes
npm run test-nodes

# Check database statistics
# Ask Claude: "Use get_database_statistics to show database metrics"

Backup Strategy

1

Regular Backups

# Daily backup cron job
0 2 * * * cp /var/lib/n8n-mcp/nodes.db /backup/nodes-$(date +\%Y\%m\%d).db
2

Before Updates

# Backup before rebuilding
cp data/nodes.db data/nodes.db.backup
npm run rebuild
3

Docker Volumes

volumes:
  - ./data:/app/data
  - ./backups:/backups

Performance Tuning

Query Performance

Average Query

~12ms response time

Full-Text Search

~20-30ms with FTS5

Template Search

~15-25ms with caching

Node Info

~5-10ms (cached)
better-sqlite3 supports FTS5 for fast full-text search:
schema.sql
-- FTS5 full-text search index for nodes
CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
  node_type,
  display_name,
  description,
  documentation,
  operations,
  content=nodes,
  content_rowid=rowid
);
sql.js does not support FTS5. Searches will use standard SQL LIKE queries with reduced performance.

Indexing Strategy

Optimized indexes for common queries:
-- Core indexes
CREATE INDEX IF NOT EXISTS idx_package ON nodes(package_name);
CREATE INDEX IF NOT EXISTS idx_ai_tool ON nodes(is_ai_tool);
CREATE INDEX IF NOT EXISTS idx_category ON nodes(category);
CREATE INDEX IF NOT EXISTS idx_community ON nodes(is_community);
CREATE INDEX IF NOT EXISTS idx_verified ON nodes(is_verified);

-- Template indexes
CREATE INDEX IF NOT EXISTS idx_template_nodes ON templates(nodes_used);
CREATE INDEX IF NOT EXISTS idx_template_updated ON templates(updated_at);

-- Configuration indexes
CREATE INDEX IF NOT EXISTS idx_config_node_type_rank 
  ON template_node_configs(node_type, rank);

Troubleshooting

Adapter Selection Issues

Symptom: NODE_MODULE_VERSION mismatch errorsCause: better-sqlite3 compiled for different Node.js versionSolution: Automatic fallback to sql.js - no action needed
# Suppress warnings
LOG_LEVEL=error
Force better-sqlite3:
USE_BETTER_SQLITE=true
Note: Will fail if compilation incompatible
Look for log messages:
Successfully initialized better-sqlite3 adapter
# or
Successfully initialized sql.js adapter

Database Corruption

1

Verify Corruption

sqlite3 data/nodes.db "PRAGMA integrity_check;"
2

Restore from Backup

cp data/nodes.db.backup data/nodes.db
3

Rebuild if Necessary

npm run rebuild

Memory Issues

Increase save interval:
SQLJS_SAVE_INTERVAL_MS=15000

Performance Degradation

Check for missing indexes:
-- List indexes
SELECT name, sql FROM sqlite_master WHERE type='index';

-- Analyze query performance
EXPLAIN QUERY PLAN SELECT * FROM nodes WHERE category = 'Communication';
Vacuum the database:
sqlite3 data/nodes.db "VACUUM;"
npm run rebuild

Next Steps

Environment Variables

All configuration options

Performance

Performance optimization guide

Troubleshooting

Database troubleshooting

API Reference

Database API documentation

Build docs developers (and LLMs) love