Remote Database
Replicache is also backend-agnostic. You can use most backend languages and frameworks, and any backend datastore that supports at least Snapshot Isolation.
Some examples of suitable datastores are: MySQL, Postgres, CockroachDB, CosmosDB, and Firebase Cloud Firestore. Some examples of non-suitable datastores are: DynamoDB and Firebase RealtimeDB.
Snapshot isolation is required for correct operation of Replicache. See Database Isolation Level for more information.
Database Setup
For this demo, we'll use pg-mem — an in-memory implementation of Postgres. This is a nice easy way to play locally, but you can easily adapt this sample to use a remote Postgres implementation like Render or Supabase.
Create a new file server/src/db.ts
with this code:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import {newDb} from 'pg-mem';
import pgp, {IDatabase, ITask} from 'pg-promise';
const {isolationLevel} = pgp.txMode;
export const serverID = 1;
async function initDB() {
console.log('initializing database...');
const db = newDb().adapters.createPgPromise();
return db;
}
function getDB() {
// Cache the database in the Node global so that it survives HMR.
if (!global.__db) {
global.__db = initDB();
}
// eslint-disable-next-line @typescript-eslint/ban-types
return global.__db as IDatabase<{}>;
}
// eslint-disable-next-line @typescript-eslint/ban-types
export type Transaction = ITask<{}>;
type TransactionCallback<R> = (t: Transaction) => Promise<R>;
// In Postgres, snapshot isolation is known as "repeatable read".
export async function tx<R>(f: TransactionCallback<R>, dbp = getDB()) {
const db = await dbp;
return await db.tx(
{
mode: new pgp.txMode.TransactionMode({
tiLevel: isolationLevel.repeatableRead,
}),
},
f,
);
}
Next
In the next section, we'll build our remote database schema.