DEV Community

Alex Spinov
Alex Spinov

Posted on

SQLite Has a Free API — The Most Deployed Database in the World

SQLite is the most deployed database in the world — 1 trillion+ databases in production. It runs in-process, needs zero configuration, and it's completely free. In 2026, it's also becoming the go-to database for web apps.

Why SQLite in 2026?

The "SQLite Renaissance" is real:

  • Turso — distributed SQLite at the edge
  • LiteFS — replicated SQLite by Fly.io
  • Litestream — streaming SQLite replication
  • D1 — Cloudflare's SQLite-based database
  • libSQL — open-source fork with more features
  • Better-sqlite3 — synchronous, 5x faster than node-sqlite3

Quick Start (Node.js)

npm install better-sqlite3
Enter fullscreen mode Exit fullscreen mode
import Database from "better-sqlite3";

const db = new Database("app.db");

// Enable WAL mode (concurrent reads while writing)
db.pragma("journal_mode = WAL");

// Create table
db.exec(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at TEXT DEFAULT (datetime('now'))
  )
`);

// Insert
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("Alice", "alice@example.com");

// Batch insert (transaction — 100x faster)
const insertMany = db.transaction((users) => {
  for (const user of users) {
    insert.run(user.name, user.email);
  }
});

insertMany([
  { name: "Bob", email: "bob@example.com" },
  { name: "Charlie", email: "charlie@example.com" },
]);

// Query
const users = db.prepare("SELECT * FROM users WHERE name LIKE ?").all("%li%");
console.log(users);

// Single row
const user = db.prepare("SELECT * FROM users WHERE id = ?").get(1);
Enter fullscreen mode Exit fullscreen mode

Full-Text Search (Built-in!)

// Create FTS5 virtual table
db.exec(`
  CREATE VIRTUAL TABLE IF NOT EXISTS articles_fts USING fts5(
    title, content, tags
  )
`);

// Insert articles
const insertArticle = db.prepare(
  "INSERT INTO articles_fts (title, content, tags) VALUES (?, ?, ?)"
);

insertArticle.run("Getting Started with SQLite", "SQLite is a lightweight database...", "sqlite database tutorial");
insertArticle.run("React State Management", "Managing state in React apps...", "react state zustand");

// Full-text search with ranking
const results = db.prepare(`
  SELECT *, rank FROM articles_fts
  WHERE articles_fts MATCH ?
  ORDER BY rank
  LIMIT 10
`).all("sqlite database");
Enter fullscreen mode Exit fullscreen mode

No Elasticsearch. No Algolia. Built into SQLite.

JSON Support

// Store JSON data
db.exec(`
  CREATE TABLE IF NOT EXISTS events (
    id INTEGER PRIMARY KEY,
    data JSON NOT NULL,
    created_at TEXT DEFAULT (datetime('now'))
  )
`);

db.prepare("INSERT INTO events (data) VALUES (json(?))").run(
  JSON.stringify({
    type: "page_view",
    page: "/pricing",
    user: { id: 123, plan: "pro" },
    metadata: { referrer: "google.com" },
  })
);

// Query JSON fields
const pageViews = db.prepare(`
  SELECT 
    json_extract(data, '$.type') as event_type,
    json_extract(data, '$.page') as page,
    json_extract(data, '$.user.plan') as plan
  FROM events
  WHERE json_extract(data, '$.type') = 'page_view'
`).all();
Enter fullscreen mode Exit fullscreen mode

Express.js API with SQLite

import express from "express";
import Database from "better-sqlite3";

const app = express();
app.use(express.json());

const db = new Database("api.db");
db.pragma("journal_mode = WAL");

db.exec(`
  CREATE TABLE IF NOT EXISTS todos (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    text TEXT NOT NULL,
    completed INTEGER DEFAULT 0,
    created_at TEXT DEFAULT (datetime('now'))
  )
`);

app.get("/api/todos", (req, res) => {
  const todos = db.prepare("SELECT * FROM todos ORDER BY created_at DESC").all();
  res.json(todos);
});

app.post("/api/todos", (req, res) => {
  const { text } = req.body;
  const result = db.prepare("INSERT INTO todos (text) VALUES (?)").run(text);
  const todo = db.prepare("SELECT * FROM todos WHERE id = ?").get(result.lastInsertRowid);
  res.status(201).json(todo);
});

app.patch("/api/todos/:id", (req, res) => {
  const { completed } = req.body;
  db.prepare("UPDATE todos SET completed = ? WHERE id = ?").run(completed ? 1 : 0, req.params.id);
  const todo = db.prepare("SELECT * FROM todos WHERE id = ?").get(req.params.id);
  res.json(todo);
});

app.delete("/api/todos/:id", (req, res) => {
  db.prepare("DELETE FROM todos WHERE id = ?").run(req.params.id);
  res.status(204).send();
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Migrations

const MIGRATIONS = [
  `CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT UNIQUE
  )`,
  `ALTER TABLE users ADD COLUMN role TEXT DEFAULT 'user'`,
  `CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)`,
  `CREATE TABLE IF NOT EXISTS posts (
    id INTEGER PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    title TEXT NOT NULL,
    content TEXT,
    created_at TEXT DEFAULT (datetime('now'))
  )`,
];

function migrate(db) {
  db.exec("CREATE TABLE IF NOT EXISTS _migrations (id INTEGER PRIMARY KEY)");
  const applied = db.prepare("SELECT MAX(id) as last FROM _migrations").get();
  const lastId = applied?.last || 0;

  const pending = MIGRATIONS.slice(lastId);
  if (pending.length === 0) return;

  const run = db.transaction(() => {
    for (let i = 0; i < pending.length; i++) {
      db.exec(pending[i]);
      db.prepare("INSERT INTO _migrations (id) VALUES (?)").run(lastId + i + 1);
    }
  });

  run();
  console.log(`Applied ${pending.length} migrations`);
}
Enter fullscreen mode Exit fullscreen mode

SQLite vs PostgreSQL vs MySQL vs MongoDB

Feature SQLite PostgreSQL MySQL MongoDB
Setup Zero (file) Server Server Server
Concurrency WAL (good reads) Excellent Good Good
JSON support Yes Yes (JSONB) Yes Native
Full-text search FTS5 (built-in) tsvector FULLTEXT Atlas Search
Replication Turso/LiteFS Built-in Built-in Built-in
Best for Single-server apps Multi-server Web apps Documents
Max size 281 TB Unlimited Unlimited Unlimited

Need to scrape data from any website and get it in structured JSON? Check out my web scraping tools on Apify — no coding required, results in minutes.

Have a custom data extraction project? Email me at spinov001@gmail.com — I build tailored scraping solutions for businesses.

Top comments (0)