SyncDBG offline-first data synchronization library.
npm install syncdbgNPM version
License: MIT
SyncDBG is a robust JavaScript/TypeScript library for building offline-first web applications. It provides a complete mechanism to store data locally in the browser, intelligently synchronize with a backend when the connection is restored, and flexibly resolve data conflicts.
Inspired by solutions like AFFiNE and PouchDB, SyncDBG was designed to be a generic, reusable, and easy-to-integrate component for any web development stack, with first-class support for React.
---
- Robust Local Persistence: Uses IndexedDB to store large volumes of structured data asynchronously without blocking the UI.
- Smart Synchronization: Automatically detects online/offline status and manages an operation queue to sync with the backend only when possible.
- Optimistic UI: Changes are instantly reflected in the UI, providing a smooth user experience even on unstable networks.
- Conflict Resolution: Supports multiple conflict resolution strategies like Last-Write-Wins, Server-Wins, or custom merge logic.
- Reactive and Simple API: An intuitive API to manage data collections and subscribe to updates, with ready-to-use React Hooks.
- Modular Architecture: Decoupled and extensible, enabling the creation of new persistence or API adapters.
---
This repository is a pnpm-managed monorepo.
| Package | NPM | Description |
|-----------------------------|-----|-----------------------------------------------------------------------------|
| @syncdbg/core | npm | The framework-agnostic core engine with all synchronization logic. |
| @syncdbg/adapter-indexeddb | npm | Persistence adapter for IndexedDB. |
| @syncdbg/react | npm | React Hooks (useSyncState, useCollection) for seamless integration. |
| @syncdbg/utils | npm | Utility functions shared across the monorepo. |
---
This guide shows how to integrate SyncDBG into a React application.
Install the required packages in your project:
``bash`
npm install @syncdbg/core @syncdbg/adapter-indexeddb @syncdbg/reactor
yarn add @syncdbg/core @syncdbg/adapter-indexeddb @syncdbg/reactor
pnpm add @syncdbg/core @syncdbg/adapter-indexeddb @syncdbg/react
---
In your application entry point (e.g., index.tsx or App.tsx), create and configure the SyncDBGClient instance:
`tsx
// src/client.ts
import { SyncDBGClient } from '@syncdbg/core';
import { IndexedDBAdapter } from '@syncdbg/adapter-indexeddb';
// Define your backend contract. SyncDBG expects a simple API contract.
const apiAdapter = {
async push(operations) {
const response = await fetch('/api/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ operations }),
});
if (!response.ok) throw new Error('Failed to push changes');
return response.json(); // Expected: { successful: string[], failed: any[] }
},
async pull(lastPulledAt) {
const response = await fetch(/api/sync?lastPulledAt=${lastPulledAt || 0});
if (!response.ok) throw new Error('Failed to fetch changes');
return response.json(); // Expected: { changes: Operation[], timestamp: number }
},
};
// Create the client instance
export const syncDBGClient = new SyncDBGClient({
persistenceAdapter: new IndexedDBAdapter({
dbName: 'my-app-db',
dbVersion: 1,
collections: ['notes', 'tasks'], // declare all collections here
}),
apiAdapter,
});
`
---
Use the SyncDBGProvider to make the client available across your React components.
`tsx
// src/App.tsx
import React from 'react';
import { SyncDBGProvider } from '@syncdbg/react';
import { syncDBGClient } from './client';
import { NotesList } from './NotesList';
function App() {
return (
My Notes (Offline-First)
);
}
export default App;
`
---
Now you can use useCollection and useNetworkStatus hooks to read and update data reactively.
`tsx
// src/NotesList.tsx
import React from 'react';
import { useCollection, useNetworkStatus } from '@syncdbg/react';
interface Note {
id: string;
title: string;
content: string;
updatedAt: string;
}
export function NotesList() {
const { data: notes, collection: notesCollection } = useCollection
const isOnline = useNetworkStatus();
const handleAddNote = () => {
const title = prompt('New note title:');
if (title) {
notesCollection.add({
title,
content: '',
updatedAt: new Date().toISOString(),
});
}
};
return (
Status: {isOnline ? 'Online' : 'Offline'}
And thatβs it! π
With these steps, your app now stores notes locally, displays them instantly, and synchronizes with the backend in the background.
---
π οΈ For Developers (Contributing)
Interested in contributing? Awesome! Follow the steps below to set up your development environment:
`bash
Clone the repo
git clone https://github.com/fmartini23/syncdbg.git
cd syncdbgInstall pnpm (if not already installed)
npm install -g pnpmInstall dependencies
pnpm installBuild all packages
pnpm buildStart development mode
pnpm dev
`This command watches all
packages/* and recompiles them automatically when changes are made.$3
-
pnpm build: Builds all packages for production.
- pnpm dev: Starts development mode for all packages.
- pnpm lint: Runs code quality checks across the project.
- pnpm format:check`: Ensures code is properly formatted with Prettier. ---
This project is licensed under the MIT License. See the LICENSE file for more details.