npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svelte-idb

v0.1.4

Published

Zero-dependency, SSR-safe, Svelte 5 runes-native IndexedDB wrapper

Readme

svelte-idb bridges the gap between the imperative, asynchronous nature of IndexedDB and the synchronous, declarative world of Svelte 5. It provides a frictionless developer experience with fully typed schemas and automatic UI updates powered by $state runes.

✨ Features

  • ⚡️ Svelte 5 Runes Native: Built from the ground up using $state and $derived for seamless, glitch-free reactivity.
  • 🛡️ SSR Safe By Design: Safely use it in SvelteKit SSR environments. Automatically no-ops or uses safe defaults on the server.
  • 🎈 Tiny & Zero-Dependency: Less than 2KB minzipped. No external libraries, just pure modern browser APIs.
  • 🏷️ First-Class TypeScript: Define your schema once and enjoy type-safe queries, stores, and autocomplete everywhere.
  • 🔄 Automatic Live Queries: Mutations (add, put, delete, clear) automatically trigger microtask-batched reactivity for optimal performance.
  • 🧩 Dual Exports: Clean Separation between core logic and Svelte-specific reactive hooks.

📦 Installation

npm install svelte-idb
# or
bun add svelte-idb
# or
pnpm add svelte-idb

🚀 Quick Start

For detailed step-by-step guides and examples, visit the documentation site.

1. Define your Database

Use createReactiveDB to define your schema, stores, and configuration. Do this in a shared file like src/lib/db.ts.

// src/lib/db.ts
import { createReactiveDB } from 'svelte-idb/svelte';

export interface Todo {
  id?: number;
  text: string;
  done: boolean;
  createdAt: number;
}

export const db = createReactiveDB({
  name: 'my-app-db',
  version: 1,
  stores: {
    todos: {
      keyPath: 'id',
      autoIncrement: true, // Auto-generates IDs for new records
    }
  }
});

2. Use Live Queries in your Components

Use the .liveAll(), .liveGet(), or .liveCount() methods. The .current property holds the reactive state and will automatically update whenever the underlying store changes.

<!-- src/routes/+page.svelte -->
<script lang="ts">
	import { db } from '$lib/db';

	// 1. Create a live query
	// This automatically fetches data and reacts to any changes
	const todos = db.todos.liveAll();

	let text = $state('');

	async function addTodo() {
		// 2. Mutate the database
		// The `todos` query will automatically re-run and update the UI!
		await db.todos.add({ text, done: false, createdAt: Date.now() });
		text = '';
	}
</script>

<div>
	<input bind:value="{text}" placeholder="New todo..." />
	<button onclick="{addTodo}">Add</button>
</div>

<!-- 3. Consume the reactive state -->
{#if todos.loading}
<p>Loading...</p>
{:else if todos.error}
<p>Error: {todos.error.message}</p>
{:else}
<ul>
	{#each todos.current as todo (todo.id)}
	<li>{todo.text}</li>
	{/each}
</ul>
{/if}

📚 API Reference

For a complete interactive API reference, visit idb.svelte-apps.me/docs.

createReactiveDB(config)

Creates and provisions an IndexedDB instance. Returns an object where each store is available as a property.

Configuration Options:

  • name (string): The database name. Must be unique per origin.
  • version (number): The schema version. Increment this whenever you change the stores object.
  • stores (object): Map of store names to their definitions (keyPath, autoIncrement).
  • ssr (string | function): How to handle SSR. Defaults to 'noop'. Can be 'throw' or a custom handler function.

Reactive Store Methods (db.storeName.*)

These methods return a LiveQuery object containing reactive $state fields: current, loading, and error.

| Method | Description | Return Type | | :----------------- | :----------------------------------------------------- | :-------------------------- | | liveAll() | Reactively lists all records in the store. | LiveQuery<T[]> | | liveGet(key) | Reactively fetches a single record by its primary key. | LiveQuery<T \| undefined> | | liveCount() | Reactively tracks the total number of records. | LiveQuery<number> |

Standard Store Methods (db.storeName.*)

All standard mutations automatically notify active LiveQueries to trigger Svelte updates. They return Promises.

| Method | Description | | :---------------- | :----------------------------------------------------- | | add(value) | Inserts a new record. Fails if the key already exists. | | put(value) | Inserts or updates a record (upsert). | | delete(key) | Removes a record by primary key. | | clear() | Removes all records from the store. | | get(key) | Fetches a single record (non-reactive). | | getAll() | Fetches all records (non-reactive). |


🛠️ Advanced

Secondary Indexes

You can define secondary indexes in your schema to enable querying by properties other than the primary key.

const db = createReactiveDB({
  name: 'my-app-db',
  version: 1,
  stores: {
    users: {
      keyPath: 'id',
      indexes: {
        byEmail: { keyPath: 'email', unique: true },
        byAge: { keyPath: 'age' }
      }
    }
  }
});

// Query using the standard async method
const adults = await db.users.getAllFromIndex('byAge', IDBKeyRange.lowerBound(18));

(Note: Reactive liveQueryByIndex is coming in Phase 3!)

SSR Safety

Because svelte-idb is designed for SvelteKit, rendering on the server (SSR) will safely "no-op" by default instead of crashing with window is not defined.

  • liveAll().current will cleanly return an empty array [] on the server.
  • loading will be false during SSR so skeleton loaders aren't triggered server-side.
  • Once the component mounts in the browser, the real IndexedDB connection is established and data hydrates automatically.

🔮 Roadmap

  • [ ] Query Builder: Chainable query API (where(index).equals(value)).
  • [ ] Transactions: Multi-store atomic operations with auto-rollback.
  • [ ] Bulk Operations: addMany, putMany, and deleteMany.
  • [ ] Cross-tab Sync: Automatic reactivity across different browser tabs using BroadcastChannel.
  • [ ] Migration Sugar: Simplified API for adding columns or renaming stores.

📄 License

MIT © Michael Obele