Skip to content

Latest commit

 

History

156 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AOSSIE

 

npm version License: GPL-3.0 OpenSSF Scorecard

Telegram Badge    X (formerly Twitter) Badge    Discord Badge    LinkedIn Badge    Youtube Badge


@aossie-org/idb-backup

A framework-agnostic, lightweight TypeScript library for exporting and importing IndexedDB databases via type-tagged JSON.


What is this?

@aossie-org/idb-backup provides a simple, portable way to back up and restore IndexedDB databases in the browser. It produces a self-describing JSON file that preserves data types that JSON.stringify normally corrupts — such as Uint8Array, bigint, and Date.

The library is designed to be framework-agnostic: it works in any browser environment and includes SSR safety guards for server-rendered frameworks like Next.js and Nuxt.


Features

  • Generic JSON export format : Structured schema + stores mapping for portable, human-readable backups
  • Type-tagged serialization : Lossless round-trip for Uint8Array, bigint, Date, ArrayBuffer, typed arrays, Set, Map, and RegExp using a __type tag convention
  • Import strategies : Choose between "overwrite" (fresh restore) or "merge" (additive sync with existing data)
  • SSR-safe : Graceful no-op guards for server-side rendering environments
  • Dual output : Ships both ESM and CJS bundles
  • Lightweight : Uses the idb wrapper over the native IndexedDB API with no heavy dependencies

Tech Stack

Category Tools
Language TypeScript 5
IndexedDB Native API + idb wrapper
Bundler tsup (ESM + CJS)
Testing vitest + happy-dom
Linting ESLint 9 + TypeScript ESLint
Formatting Prettier

Architecture

graph TD
    A["@aossie-org/idb-backup"] --> B["src/core"]
    A --> C["src/serialization"]
    A --> D["src/types"]
    A --> E["src/utils"]

    B --> B1["exporter.ts — exportDB()"]
    B --> B2["importer.ts — importDB()"]
    B --> B3["migrations.ts — future schema migrations"]

    C --> C1["index.ts — serialize() / deserialize()"]

    D --> D1["index.ts — ExportFormat, TaggedValue, etc."]

    E --> E1["ssr.ts — isBrowser(), assertBrowser()"]
    E --> E2["file.ts — downloadJSON(), readFileAsJSON()"]
Loading

Export Format

The library produces a self-describing JSON structure:

{
  "backupVersion": 1,
  "databaseName": "my-app-db",
  "databaseVersion": 3,
  "exportedAt": "2025-06-01T12:00:00.000Z",
  "schema": {
    "messages": {
      "keyPath": "id",
      "autoIncrement": false,
      "indexes": [
        { "name": "by-timestamp", "keyPath": "timestamp", "unique": false }
      ]
    }
  },
  "stores": {
    "messages": [
      {
        "key": "msg-001",
        "value": {
          "id": "msg-001",
          "payload": { "__type": "u8", "value": "SGVsbG8gV29ybGQ=" },
          "timestamp": { "__type": "date", "value": "2025-06-01T12:00:00.000Z" },
          "fee": { "__type": "bigint", "value": "1000000000000000000" }
        }
      }
    ]
  }
}

Tagged Types

Source Type __type Serialized value
Uint8Array "u8" Base64-encoded string
bigint "bigint" String representation
Date "date" ISO 8601 string
ArrayBuffer "buffer" Base64-encoded string
Other typed arrays, DataView "typed_array" { "type": "<name>", "data": "<base64>" }
Set "set" Array of serialized items
Map "map" Array of serialized [key, value] pairs
RegExp "regex" { "source": "...", "flags": "..." }
Plain object with its own __type key "object" The object's serialized fields (escapes records that would look like a tag)

All other JSON-safe values (strings, numbers, booleans, nulls, plain objects, arrays) pass through unchanged.


Getting Started

Prerequisites

  • Node.js >= 20
  • npm (ships with Node.js)

Installation

  1. Clone the repository
git clone https://github.com/AOSSIE-Org/IndexedDB-Import-Export.git
cd IndexedDB-Import-Export
  1. Install dependencies
npm install
  1. Build the library
npm run build
  1. Run tests
npm test

Available Scripts

Script Description
npm run build Bundle the library with tsup (ESM + CJS + type declarations)
npm test Run the test suite with Vitest
npm run test:watch Run tests in watch mode during development
npm run lint Lint source and test files with ESLint
npm run format Auto-format code with Prettier
npm run format:check Check formatting without modifying files

Usage

Note: The core API is under active development. The examples below show the intended usage once the feature PRs are merged.

Export a Database

import { exportDB } from '@aossie-org/idb-backup';

const backup = await exportDB({
  dbName: 'my-app-db',
  // Optional: export only specific stores
  storeNames: ['messages', 'contacts'],
});

console.log(JSON.stringify(backup, null, 2));

Import a Database

import { importDB } from '@aossie-org/idb-backup';

// Overwrite: delete existing data and restore from backup
await importDB({
  dbName: 'my-app-db',
  backupData: backup,
  strategy: 'overwrite',
});

// Merge: keep existing data and add/update from backup
await importDB({
  dbName: 'my-app-db',
  backupData: backup,
  strategy: 'merge',
});

// Selective restore: restore only the listed stores, leaving the rest of the
// database alone. Pairs naturally with 'merge'.
await importDB({
  dbName: 'my-app-db',
  backupData: backup,
  strategy: 'merge',
  storeNames: ['messages', 'contacts'],
});

// Inspect before importing: return false to abort with nothing written
await importDB({
  dbName: 'my-app-db',
  backupData: backup,
  strategy: 'overwrite',
  onBeforeImport: (summary) => {
    return confirm(
      `Restore ${summary.recordCounts.messages ?? 0} messages from ` +
        `${summary.databaseName}, exported ${summary.exportedAt}?`
    );
  },
});

Note: storeNames scopes both schema and records, mirroring exportDB. An excluded store is neither populated nor created, so importing with storeNames is equivalent to importing a backup that was exported with the same selection. Under merge, an excluded store that already exists is left untouched and one that is missing stays missing. Under overwrite — which deletes and recreates the database — an excluded store is absent afterwards even if it existed before, so prefer merge for a partial restore unless the selected stores are meant to be the whole database. Names not present in the backup are ignored, and an empty array selects nothing at all — no records restored and no stores created, so under overwrite the result is an empty database.

Download as JSON File

import { downloadJSON } from '@aossie-org/idb-backup';

downloadJSON(backup, 'my-backup.json');

Read a JSON Backup File

import { readFileAsJSON } from '@aossie-org/idb-backup';

const fileInput = document.querySelector<HTMLInputElement>('#file-input');
const file = fileInput!.files![0];
const backup = await readFileAsJSON(file);

Repository Links


Contributing

Contributions are welcome! If you would like to contribute, please refer to CONTRIBUTING.md.


Maintainers

See MAINTAINERS.md for the full list of Mentors and Maintainers for this repository.


Privacy

The library collects no data, makes no network requests, and stores everything locally on the user's device. See PRIVACY.md for details — including a note on the fact that exported backups are plain, unencrypted JSON.


License

This project is licensed under the GNU General Public License v3.0. See the LICENSE file for details.


Contributors

Thanks to everyone who has contributed to this project.

Contributors

© 2025 AOSSIE

About

Library and Component to make it easier to import and export from IndexedDB

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages