skills/sqlite/SKILL.md
SQLite database commands, queries, and embedded database patterns. Use when user mentions "sqlite", "sqlite3", "embedded database", "local database", "lightweight db", "sqlite schema", "sqlite backup", "mobile database", or working with .db/.sqlite files.
npx skillsauth add 1mangesh1/dev-skills-collection sqliteInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
sqlite3 myapp.db # open or create a database
sqlite3 :memory: # in-memory database
sqlite3 myapp.db ".tables" # one-shot command
sqlite3 myapp.db < schema.sql # run SQL from file
Common dot-commands inside the shell:
.tables -- list all tables
.schema -- show CREATE statements for all tables
.schema users -- show CREATE for specific table
.headers on -- show column headers in output
.mode column -- aligned columns (also: csv, json, table, line, tabs)
.width 20 30 10 -- set column widths for column mode
.databases -- list attached databases
.indexes users -- list indexes for a table
.quit -- exit
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY, -- alias for rowid, auto-increments
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
total REAL NOT NULL,
status TEXT DEFAULT 'pending',
created_at TEXT DEFAULT (datetime('now'))
);
INSERT INTO users (name, email) VALUES ('Alice', '[email protected]');
INSERT INTO orders (user_id, total, status)
VALUES (1, 49.99, 'completed'), (1, 25.00, 'pending'), (2, 120.00, 'completed');
UPDATE users SET email = '[email protected]' WHERE id = 1;
DELETE FROM orders WHERE status = 'pending' AND created_at < datetime('now', '-30 days');
RETURNING clause available in 3.35.0+. Check with sqlite3 --version.
SELECT o.id, u.name, o.total
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.status = 'completed';
SELECT u.name, COALESCE(SUM(o.total), 0) AS lifetime_value
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.name;
SELECT * FROM users
WHERE id IN (
SELECT user_id FROM orders GROUP BY user_id HAVING SUM(total) > 100
);
SELECT status, COUNT(*) AS cnt, ROUND(AVG(total), 2) AS avg_total
FROM orders GROUP BY status HAVING cnt > 1 ORDER BY avg_total DESC;
WITH monthly AS (
SELECT strftime('%Y-%m', created_at) AS month, SUM(total) AS revenue
FROM orders WHERE status = 'completed' GROUP BY 1
)
SELECT month, revenue,
revenue - LAG(revenue) OVER (ORDER BY month) AS change
FROM monthly;
SELECT user_id, total,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY total DESC) AS rn,
SUM(total) OVER (PARTITION BY user_id) AS user_total
FROM orders;
sqlite3 -header -csv myapp.db "SELECT * FROM users;" > users.csv
sqlite3 -json myapp.db "SELECT * FROM users;"
sqlite3 -header -column myapp.db "SELECT * FROM users;"
Inside the shell:
.mode csv -- comma-separated
.mode json -- JSON array of objects
.mode column -- aligned columns
.mode table -- ASCII table borders (3.36+)
.mode line -- one value per line
.separator "\t" -- custom separator for list mode
# Export
sqlite3 -header -csv myapp.db "SELECT * FROM users;" > users.csv
# Import into existing table
sqlite3 myapp.db <<'EOF'
.mode csv
.import users.csv users
EOF
For large imports, wrap in a transaction for speed:
BEGIN;
.mode csv
.import large_file.csv target_table
COMMIT;
CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_orders_status_date ON orders(status, created_at);
CREATE UNIQUE INDEX idx_users_email ON users(email);
EXPLAIN QUERY PLAN SELECT * FROM orders WHERE user_id = 1;
Key things in the output:
PRAGMA journal_mode=WAL; -- returns "wal" on success
PRAGMA busy_timeout=5000; -- wait up to 5s instead of failing immediately
-wal and -shm files alongside the databasePRAGMA wal_checkpoint(TRUNCATE);.backup main backup.db -- online backup (safe during use)
.dump -- full SQL text dump
.dump users -- dump a single table
sqlite3 myapp.db .dump > full_dump.sql # dump to file
sqlite3 restored.db < full_dump.sql # restore from dump
VACUUM rebuilds the database file, reclaiming space:
VACUUM; -- rebuild in place
VACUUM INTO 'compact.db'; -- compacted copy (3.27+)
Available in SQLite 3.38+ (built-in) or via the JSON1 extension:
CREATE TABLE events (id INTEGER PRIMARY KEY, data TEXT NOT NULL);
INSERT INTO events (data)
VALUES ('{"type":"click","page":"/home","tags":["mobile","v2"]}');
-- Extract values
SELECT json_extract(data, '$.type') AS event_type FROM events;
SELECT data->>'$.page' AS page FROM events; -- ->> operator (3.38+)
-- Iterate over arrays
SELECT e.id, j.value AS tag
FROM events e, json_each(json_extract(e.data, '$.tags')) j;
-- Modify JSON
UPDATE events SET data = json_set(data, '$.processed', true) WHERE id = 1;
-- Build JSON in queries
SELECT json_object('id', id, 'name', name) FROM users;
SELECT json_group_array(json_object('id', id, 'name', name)) FROM users;
CREATE VIRTUAL TABLE articles_fts USING fts5(title, body, content=articles, content_rowid=id);
-- Populate from existing table
INSERT INTO articles_fts(rowid, title, body) SELECT id, title, body FROM articles;
-- Search with boolean operators
SELECT *, rank FROM articles_fts WHERE articles_fts MATCH 'database AND performance' ORDER BY rank;
-- Highlight matches
SELECT highlight(articles_fts, 1, '<b>', '</b>') FROM articles_fts WHERE articles_fts MATCH 'sqlite';
-- Keep in sync with triggers
CREATE TRIGGER articles_ai AFTER INSERT ON articles BEGIN
INSERT INTO articles_fts(rowid, title, body) VALUES (new.id, new.title, new.body);
END;
CREATE TRIGGER articles_ad AFTER DELETE ON articles BEGIN
INSERT INTO articles_fts(articles_fts, rowid, title, body)
VALUES ('delete', old.id, old.title, old.body);
END;
SQLite stores dates as TEXT, REAL, or INTEGER. Built-in functions handle ISO-8601 strings:
SELECT datetime('now'); -- 2025-01-15 08:30:00
SELECT date('now', '-7 days'); -- 7 days ago
SELECT strftime('%Y-%m', 'now'); -- current year-month
SELECT strftime('%s', 'now'); -- unix timestamp
SELECT datetime('2025-01-15', '+3 months', '-1 day'); -- date arithmetic
SELECT julianday('now') - julianday(created_at) AS days_old FROM users;
ATTACH DATABASE 'archive.db' AS archive;
SELECT * FROM main.users u JOIN archive.orders o ON o.user_id = u.id;
INSERT INTO archive.orders SELECT * FROM main.orders WHERE created_at < '2024-01-01';
DELETE FROM main.orders WHERE created_at < '2024-01-01';
DETACH DATABASE archive;
-- Performance
PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL; -- faster writes (safe with WAL)
PRAGMA cache_size=-64000; -- 64MB page cache (negative = KB)
PRAGMA mmap_size=268435456; -- memory-map up to 256MB
PRAGMA temp_store=MEMORY; -- temp tables in memory
-- Integrity
PRAGMA foreign_keys=ON; -- enforce foreign keys (off by default!)
PRAGMA integrity_check; -- full database integrity scan
-- Info
PRAGMA table_info(users); -- column details
PRAGMA index_list(users); -- indexes on a table
PRAGMA compile_options; -- build-time options (check for JSON, FTS5)
CREATE TABLE config (
key TEXT PRIMARY KEY, value TEXT,
updated_at TEXT DEFAULT (datetime('now'))
);
INSERT OR REPLACE INTO config (key, value) VALUES ('theme', 'dark');
SELECT value FROM config WHERE key = 'theme';
CREATE TABLE cache (key TEXT PRIMARY KEY, value TEXT, expires_at TEXT);
INSERT OR REPLACE INTO cache (key, value, expires_at)
VALUES ('api:/users', '{"data":[...]}', datetime('now', '+1 hour'));
SELECT value FROM cache WHERE key = 'api:/users' AND expires_at > datetime('now');
DELETE FROM cache WHERE expires_at <= datetime('now');
CREATE TABLE history (
id INTEGER PRIMARY KEY, command TEXT NOT NULL,
args TEXT, exit_code INTEGER,
ran_at TEXT DEFAULT (datetime('now'))
);
SELECT command, args, ran_at FROM history ORDER BY ran_at DESC LIMIT 20;
SELECT command, COUNT(*) AS cnt FROM history GROUP BY command ORDER BY cnt DESC;
sqlite3 test.db < schema.sql && sqlite3 test.db < seed.sql
# In-memory: Python sqlite3.connect(":memory:") / Node new Database(":memory:")
BEGIN;
INSERT INTO users (id, name, email) VALUES
(1, 'Test User', '[email protected]'),
(2, 'Admin', '[email protected]');
INSERT INTO orders (user_id, total, status) VALUES
(1, 99.99, 'completed'), (2, 50.00, 'pending');
COMMIT;
tools
Parallel execution with xargs, GNU parallel, and batch processing patterns. Use when user mentions "xargs", "parallel", "batch processing", "run in parallel", "parallel execution", "process list of files", "bulk operations", "concurrent commands", "map over files", or running commands on multiple inputs.
development
WebSocket implementation for real-time bidirectional communication. Use when user mentions "websocket", "ws://", "wss://", "real-time", "live updates", "chat application", "socket.io", "Server-Sent Events", "SSE", "push notifications", "live data", "streaming data", "bidirectional communication", "websocket server", "reconnection", or building real-time features.
tools
Frontend bundler configuration for Webpack and Vite. Use when user mentions "webpack", "vite", "bundler", "vite config", "webpack config", "code splitting", "tree shaking", "hot module replacement", "HMR", "build optimization", "bundle size", "chunk splitting", "loader", "plugin", "esbuild", "rollup", "dev server", or configuring JavaScript build tools.
tools
VS Code configuration, extensions, keybindings, and workspace optimization. Use when user mentions "vscode", "vs code", "vscode settings", "vscode extensions", "keybindings", "code editor", "workspace settings", "settings.json", "launch.json", "tasks.json", "vscode snippets", "devcontainer", "remote development", or customizing their VS Code setup.