A Whole Database in a Single File — Free of Servers
SQLite
SQLite is perfect for prototypes, single-server apps, and learning. Node 22+ has it built-in.
What you'll learn
- Open a SQLite database
- Create a table, insert, query
- Use prepared statements
SQLite stores the entire database in a single file. No server process. No connection strings. Ridiculously fast for one-machine apps.
Two Ways to Use It
Built-in (Node 22.5+, experimental)
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("app.db");
db.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
`);
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("Ada", "ada@example.com");
const get = db.prepare("SELECT * FROM users WHERE id = ?");
console.log(get.get(1)); Run with node --experimental-sqlite app.mjs.
better-sqlite3 (stable, recommended for production)
npm install better-sqlite3 import Database from "better-sqlite3";
const db = new Database("app.db");
db.prepare(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
`).run();
db.prepare("INSERT INTO users (name, email) VALUES (?, ?)")
.run("Ada", "ada@example.com");
const user = db.prepare("SELECT * FROM users WHERE id = ?").get(1);
console.log(user); Note: it’s synchronous. SQLite reads/writes are so fast that async overhead would dominate. Just call it directly.
Prepared Statements
Always use parameterized queries — never string-concat user input:
// ✗ SQL injection
db.prepare(`SELECT * FROM users WHERE email = '${email}'`).get();
// ✓ safe
db.prepare("SELECT * FROM users WHERE email = ?").get(email); Transactions
const insertMany = db.transaction((users) => {
for (const u of users) {
db.prepare("INSERT INTO users (name, email) VALUES (?, ?)").run(u.name, u.email);
}
});
insertMany([
{ name: "Ada", email: "ada@example.com" },
{ name: "Linus", email: "linus@example.com" },
]); All-or-nothing, very fast (one fsync at the end).
When to Use SQLite
- Prototypes, learning, demos
- Single-server apps with modest write load (small SaaS, internal tools)
- Edge / CDN deployments (Cloudflare D1, Turso)
- Local-first apps
When not to: multi-writer high-concurrency apps. SQLite can do ~10K writes/sec on good hardware, but it serializes writes — under heavy concurrent write load, you’ll want Postgres.
PostgreSQL →