Skip to main content

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.

info

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.