SQLite
SQLite
Section titled “SQLite”This guide covers how to connect Tabula Lens to SQLite databases. SQLite is a serverless, self-contained database engine ideal for local development, embedded applications, and small to medium workloads.
Installation
Section titled “Installation”Install @tabula-lens/node and the SQLite driver:
npm i @tabula-lens/node better-sqlite3pnpm add @tabula-lens/node better-sqlite3yarn add @tabula-lens/node better-sqlite3On some platforms, better-sqlite3 requires a C++ compiler and Python to build native bindings. See the better-sqlite3 documentation for platform-specific build instructions.
Database Connection
Section titled “Database Connection”Connection String Format
Section titled “Connection String Format”Set your database connection string as an environment variable:
# File-based databaseDATABASE_URL="./database.sqlite"
# In-memory database (useful for tests)DATABASE_URL=":memory:"
# Explicit sqlite protocolDATABASE_URL="sqlite:./database.sqlite"Connection String Components
Section titled “Connection String Components”SQLite connection strings are simpler than network databases. Tabula Lens accepts:
./path/to/database.sqlitesqlite:./path/to/database.sqlite:memory:Components:
- File path - Relative or absolute path to the SQLite database file
:memory:- In-memory database (data is lost when the process exits)sqlite:protocol - Optional protocol prefix
Connection Parameters
Section titled “Connection Parameters”Common connection parameters:
# Enable foreign key constraintsDATABASE_URL="./database.sqlite?foreign_keys=true"
# Set busy timeout (milliseconds)DATABASE_URL="./database.sqlite?busyTimeout=5000"
# Journal mode for concurrencyDATABASE_URL="./database.sqlite?journal_mode=WAL"
# Synchronous modeDATABASE_URL="./database.sqlite?synchronous=NORMAL"For better concurrency, use Write-Ahead Logging (WAL) mode:
DATABASE_URL="./database.sqlite?journal_mode=WAL"Connection Patterns
Section titled “Connection Patterns”Local Development
Section titled “Local Development”import { TabulaLens } from '@tabula-lens/node';
const tabulaLens = new TabulaLens({ url: process.env.DATABASE_URL, type: 'sqlite',});
// Test connectionconst tables = await tabulaLens.getTables();console.log('Available tables:', tables);Production
Section titled “Production”import { TabulaLens } from '@tabula-lens/node';
const tabulaLens = new TabulaLens({ url: process.env.DATABASE_URL, type: 'sqlite', logLevel: 'error', logFormat: 'json', sensitiveDataMasking: true, enableRequestLogging: true,});With Custom Logger
Section titled “With Custom Logger”import { TabulaLens } from '@tabula-lens/node';import winston from 'winston';
const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.Console(), new winston.transports.File({ filename: 'database.log' }), ],});
const tabulaLens = new TabulaLens({ url: process.env.DATABASE_URL, type: 'sqlite', logger: { debug: (msg) => logger.debug(msg), info: (msg) => logger.info(msg), warn: (msg) => logger.warn(msg), error: (msg) => logger.error(msg), },});Connection Pooling
Section titled “Connection Pooling”SQLite with better-sqlite3 uses a single database connection per Knex instance. Unlike client-server databases, SQLite does not use a network connection pool. Concurrency is handled through SQLite’s file locking and WAL mode.
Concurrency Best Practices
Section titled “Concurrency Best Practices”const tabulaLens = new TabulaLens({ url: process.env.DATABASE_URL, type: 'sqlite',});For read-heavy workloads, enable WAL mode through the connection string:
DATABASE_URL="./database.sqlite?journal_mode=WAL"Busy Timeout
Section titled “Busy Timeout”Set a busy timeout to avoid SQLITE_BUSY errors under concurrent access:
DATABASE_URL="./database.sqlite?busyTimeout=5000"Database Setup
Section titled “Database Setup”Creating a Database
Section titled “Creating a Database”SQLite databases are created automatically when the file is first accessed. You can create tables directly after connecting.
# Ensure the directory existsmkdir -p ./dataCreating Tables
Section titled “Creating Tables”-- Create users tableCREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);
-- Create products tableCREATE TABLE products ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, price REAL NOT NULL, description TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP);
-- Create orders tableCREATE TABLE orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, total REAL NOT NULL, status TEXT DEFAULT 'pending', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id));Adding Sample Data
Section titled “Adding Sample Data”-- Insert sample usersINSERT INTO users (name, email) VALUES
-- Insert sample productsINSERT INTO products (name, price, description) VALUES ('Product A', 29.99, 'Description for Product A'), ('Product B', 49.99, 'Description for Product B'), ('Product C', 19.99, 'Description for Product C');
-- Insert sample ordersINSERT INTO orders (user_id, total, status) VALUES (1, 29.99, 'completed'), (2, 49.99, 'pending'), (1, 19.99, 'shipped');User Permissions
Section titled “User Permissions”SQLite does not have a user permission system like client-server databases. Access control is handled at the file-system level.
File Permissions
Section titled “File Permissions”Restrict access to the database file:
# Set restrictive permissions on Linux/macOSchmod 600 ./database.sqlite
# Ensure the parent directory is writable by the applicationchmod 700 ./dataOn Windows, use NTFS permissions to restrict access to the database file and directory.
Application-Level Security
Section titled “Application-Level Security”Since SQLite relies on file-system security:
- Run the application process under a dedicated user account
- Restrict database file access to that user account
- Store backups in a location with restricted access
- Avoid placing the database file inside publicly accessible directories
Security Best Practices
Section titled “Security Best Practices”Environment Variables
Section titled “Environment Variables”Use environment variables for connection strings:
# .env fileDATABASE_URL=./database.sqlite// Load environment variablesimport dotenv from 'dotenv';dotenv.config();
const tabulaLens = new TabulaLens({ url: process.env.DATABASE_URL, type: 'sqlite',});Connection Security
Section titled “Connection Security”// Production configuration with securityconst tabulaLens = new TabulaLens({ url: process.env.DATABASE_URL, type: 'sqlite', logLevel: 'error', logFormat: 'json', sensitiveDataMasking: true, enableRequestLogging: true,});File Security
Section titled “File Security”- Restrict file permissions: Set appropriate file system permissions
- Use dedicated directories: Store databases in dedicated, secure directories
- Regular backups: Implement regular backup strategies
- Encrypt sensitive data: Consider encryption for sensitive data at rest
- Monitor file access: Monitor and log file access patterns
Concurrency Considerations
Section titled “Concurrency Considerations”- Use WAL mode: Enable Write-Ahead Logging for better concurrency
- Set busy timeout: Configure appropriate busy timeout values
- Handle conflicts: Implement proper error handling for
SQLITE_BUSYerrors - Limit concurrent writes: Minimize concurrent write operations
- Consider connection limits: For high-concurrency scenarios, consider client-server databases
Performance Optimization
Section titled “Performance Optimization”WAL Mode
Section titled “WAL Mode”Enable Write-Ahead Logging for better concurrency:
DATABASE_URL="./database.sqlite?journal_mode=WAL"WAL mode allows multiple readers and a single writer to operate concurrently.
Synchronous Mode
Section titled “Synchronous Mode”Adjust synchronous mode for performance vs. durability trade-offs:
# Full durability (default)DATABASE_URL="./database.sqlite?synchronous=FULL"
# Normal mode (better performance, still safe)DATABASE_URL="./database.sqlite?synchronous=NORMAL"
# Off mode (maximum performance, risk of data loss on crash)DATABASE_URL="./database.sqlite?synchronous=OFF"Query Optimization
Section titled “Query Optimization”- Create indexes: Add indexes on frequently queried columns
- Use transactions: Group related operations in transactions
- **Avoid SELECT ***: Select only needed columns
- Use appropriate data types: Choose the right data type for each column
- Analyze query plans: Use
EXPLAIN QUERY PLANto analyze queries
Troubleshooting
Section titled “Troubleshooting”Connection Issues
Section titled “Connection Issues”SQLITE_CANTOPEN
Ensure the database file path is correct and the parent directory exists and is writable.
SQLITE_BUSY
This occurs when the database is locked by another process. Increase the busy timeout or enable WAL mode for better concurrency.
Performance Issues
Section titled “Performance Issues”Slow queries
- Check for missing indexes
- Use
EXPLAIN QUERY PLANto analyze query execution - Consider enabling WAL mode for better concurrency
- Optimize your database schema and queries
Build Issues
Section titled “Build Issues”Native module compilation errors
On some platforms, better-sqlite3 requires build tools:
- Windows: Install Windows Build Tools
- macOS: Install Xcode Command Line Tools
- Linux: Install build-essential and python3
See the better-sqlite3 documentation for platform-specific instructions.