← All work

Repolayer

Write your data access once. Start on SQLite, move to Postgres, MySQL or MariaDB by changing one line, with a conformance suite proving every adapter behaves the same.

Most of my projects start on a single SQLite file, and some of them eventually need a real database server. Repolayer is the data layer I built so that move is a config change instead of a rewrite: a small TypeScript library with a typed Repo<T> interface and four adapters that behave identically. It also powers the data layer of this site.

const repo = await createRepo<Puzzle>({
  driver: 'sqlite',            // or 'postgres', 'mysql', 'mariadb'
  table: 'puzzles',
  schema: puzzleSchema,
  connection: { file: './data.db' },
});

await repo.findMany({ where: { solved: false }, limit: 20 });

Highlights

  • Proven, not promised. One shared conformance suite runs against every adapter. A green build is the evidence that they behave the same.
  • Zero native dependencies. SQLite runs on Node's built-in node:sqlite. The Postgres and MySQL drivers are optional and loaded lazily.
  • Testable. An in-memory MemoryRepo passes the same suite, so unit tests need no database.
  • Built for real data. Transactions, streaming, keyset pagination, and TypeScript types inferred from a plain schema object.

Not an ORM, on purpose

No query builder, no migrations, no relations. The query shape is kept small because that restriction is what lets four different engines behave the same way.

Read the full write-up on dev.to.

TYPESCRIPT
NPM
2026