← Back to the Build Your Homepage series
🟒
EPISODE 06
Persisting state Β· read/write JSON Β· race conditions

File-based Database (JSON)

Before introducing a real database, persist data to disk as JSON. Learn the limitations (concurrency, scale) and when to graduate to SQLite/PostgreSQL.

persistenceJSONfslowdb
Duration
⏱ About 1.5 hours
Level
πŸ“Š Intermediate
Prerequisite
🎯 node-05
OUTCOME
Persist a REST API's data to a JSON file (good enough for prototypes)

What you'll learn

  • 1Read/write a JSON file with fs.promises
  • 2Wrap I/O in helper functions
  • 3Recognize race-condition limitations
  • 4Migrate naturally to a real database later

1. A Tiny JSON Store

javascript
import fs from "node:fs/promises";
const FILE = "./data.json";

async function load() {
  try {
    return JSON.parse(await fs.readFile(FILE, "utf8"));
  } catch {
    return { tasks: [], nextId: 1 };
  }
}

async function save(data) {
  await fs.writeFile(FILE, JSON.stringify(data, null, 2));
}

const db = await load();
db.tasks.push({ id: db.nextId++, title: "buy milk" });
await save(db);

2. Integrate with Express

javascript
app.get("/tasks", async (req, res) => {
  const db = await load();
  res.json(db.tasks);
});
app.post("/tasks", async (req, res) => {
  const db = await load();
  const task = { id: db.nextId++, title: req.body.title, done: false };
  db.tasks.push(task);
  await save(db);
  res.status(201).json(task);
});

3. Limitations

  • Two requests writing at the same time can lose data (race condition)
  • Whole file is read/rewritten on every operation β€” slow past a few MB
  • No query language, no indexes
  • Fine for: personal tools, prototypes, low-traffic dashboards
  • Not fine for: any production app with concurrent users
πŸ’‘

Next module β€” Databases β€” graduates from JSON to SQLite (single file but with SQL) and beyond.

Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub β†—