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

@objectql/driver-localstorage

v4.1.0

Published

LocalStorage driver for ObjectQL - Browser-based persistent storage

Downloads

54

Readme

LocalStorage Driver for ObjectQL

Production-Ready - Browser-based persistent storage driver for client-side applications.

Overview

The LocalStorage Driver is a production-ready implementation of the ObjectQL Driver interface that persists data to browser localStorage. It provides full query support with automatic serialization, making it perfect for client-side applications that need data persistence across sessions.

Features

  • Browser LocalStorage Persistence - Data survives page refreshes
  • Full Query Support - Filters, sorting, pagination, field projection
  • Automatic Serialization - JSON serialization/deserialization
  • Namespace Support - Avoid key conflicts with multiple apps
  • Storage Quota Management - Handles quota exceeded errors
  • Bulk Operations - createMany, updateMany, deleteMany
  • TypeScript - Full type safety and IntelliSense support
  • Zero Dependencies - Only depends on @objectql/types

Use Cases

This driver is perfect for:

  1. Progressive Web Apps (PWAs) - Offline-first applications
  2. Client-Side Web Applications - Persistent user data without a backend
  3. Browser Extensions - Local data storage for extensions
  4. User Preferences - Save settings and configuration
  5. Offline Mode - Cache data for offline access
  6. Prototyping - Quick development without backend setup

Installation

# Using pnpm (recommended)
pnpm add @objectql/driver-localstorage

# Using npm
npm install @objectql/driver-localstorage

# Using yarn
yarn add @objectql/driver-localstorage

Basic Usage

import { ObjectQL } from '@objectql/core';
import { LocalStorageDriver } from '@objectql/driver-localstorage';

// Initialize the driver
const driver = new LocalStorageDriver();

// Create ObjectQL instance
const app = new ObjectQL({
  datasources: { default: driver }
});

// Register your schema
app.registerObject({
  name: 'tasks',
  fields: {
    title: { type: 'text', required: true },
    completed: { type: 'boolean', defaultValue: false },
    priority: { type: 'select', options: ['low', 'medium', 'high'] }
  }
});

await app.init();

// Use it!
const ctx = app.createContext({ isSystem: true });
const repo = ctx.object('tasks');

// Create (persists to localStorage)
const task = await repo.create({
  title: 'Build awesome app',
  priority: 'high'
});

// Data persists across page refreshes!

Configuration Options

Basic Configuration

const driver = new LocalStorageDriver();

With Custom Namespace

const driver = new LocalStorageDriver({
  namespace: 'myapp'  // Avoids conflicts with other apps
});

With Initial Data

const driver = new LocalStorageDriver({
  initialData: {
    users: [
      { id: '1', name: 'Alice', email: '[email protected]' },
      { id: '2', name: 'Bob', email: '[email protected]' }
    ]
  }
});

With Strict Mode

const driver = new LocalStorageDriver({
  strictMode: true  // Throws errors for missing records
});

For Testing (with mock storage)

// Use with jsdom or mock localStorage
const driver = new LocalStorageDriver({
  storage: mockLocalStorage
});

How Data is Stored

Records are stored as JSON strings with keys formatted as:

{namespace}:{objectName}:{id}

Example:

objectql:tasks:task-1234567890-1 → {"id":"task-1234567890-1","title":"Build app",...}

Storage Limits

LocalStorage typically has a 5-10MB limit per origin. The driver handles quota exceeded errors gracefully:

try {
  await driver.create('tasks', { /* large data */ });
} catch (error) {
  if (error.code === 'STORAGE_QUOTA_EXCEEDED') {
    // Handle quota exceeded
    console.log('Storage full! Please clear some data.');
  }
}

API Reference

The LocalStorage Driver implements the full Driver interface. See the Memory Driver documentation for detailed API examples, as both drivers support the same query operations.

Key Methods

  • find(objectName, query, options) - Query records
  • findOne(objectName, id, query, options) - Get single record
  • create(objectName, data, options) - Create record
  • update(objectName, id, data, options) - Update record
  • delete(objectName, id, options) - Delete record
  • count(objectName, filters, options) - Count records
  • distinct(objectName, field, filters, options) - Get unique values
  • createMany, updateMany, deleteMany - Bulk operations
  • clear() - Clear all data for this namespace
  • getSize() - Get number of stored records

Supported Query Operators

All standard ObjectQL query operators are supported:

  • Comparison: =, !=, >, >=, <, <=
  • Set: in, nin
  • String: contains, startswith, endswith
  • Range: between
  • Logical: and, or

Examples

Offline Task Manager

import { LocalStorageDriver } from '@objectql/driver-localstorage';

// Initialize driver with app namespace
const driver = new LocalStorageDriver({
  namespace: 'task-manager'
});

// Create tasks (persists automatically)
await driver.create('tasks', {
  title: 'Review pull request',
  completed: false,
  dueDate: '2026-01-20'
});

// Query tasks
const pending = await driver.find('tasks', {
  filters: [['completed', '=', false]],
  sort: [['dueDate', 'asc']]
});

// Update task
await driver.update('tasks', taskId, {
  completed: true
});

// Data persists across page refreshes!

User Preferences

const driver = new LocalStorageDriver({
  namespace: 'app-preferences'
});

// Save preferences
await driver.create('settings', {
  id: 'user-settings',
  theme: 'dark',
  language: 'en',
  notifications: true
});

// Load preferences on next visit
const settings = await driver.findOne('settings', 'user-settings');

Multiple Namespaces

// Separate drivers for different parts of your app
const userDriver = new LocalStorageDriver({ namespace: 'user-data' });
const cacheDriver = new LocalStorageDriver({ namespace: 'api-cache' });

await userDriver.create('profile', { name: 'Alice' });
await cacheDriver.create('posts', { title: 'Cached post' });

// Clear cache without affecting user data
await cacheDriver.clear();

Comparison with Other Drivers

| Feature | LocalStorage | Memory | SQL | MongoDB | |---------|-------------|--------|-----|---------| | Persistence | ✅ Browser | ❌ No | ✅ Database | ✅ Database | | Environment | 🌐 Browser | 🌐 Universal | 🖥️ Server | 🖥️ Server | | Setup Required | ❌ None | ❌ None | ✅ Database | ✅ Database | | Storage Limit | ~5-10MB | RAM | Large | Large | | Performance | 🏃 Fast | ⚡ Fastest | 🐢 Slower | 🏃 Fast | | Dependencies | 0 | 0 | 2-3 | 1 |

Limitations

  1. Browser Only - Requires browser localStorage API
  2. Storage Quota - Limited to ~5-10MB (varies by browser)
  3. Synchronous API - LocalStorage API is synchronous (blocking)
  4. Single Tab - Changes not immediately visible across tabs
  5. String Only - All data serialized to JSON strings
  6. No Indexes - Queries scan all records (O(n))

Best Practices

1. Use Namespaces

// Good - prevents conflicts
const driver = new LocalStorageDriver({
  namespace: 'my-app-v1'
});

// Avoid - may conflict with other apps
const driver = new LocalStorageDriver();

2. Handle Storage Errors

try {
  await driver.create('tasks', largeData);
} catch (error) {
  if (error.code === 'STORAGE_QUOTA_EXCEEDED') {
    // Prompt user to clear old data
    await driver.deleteMany('tasks', [
      ['completed', '=', true]
    ]);
  }
}

3. Clear Old Data

// Clear completed tasks older than 30 days
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

await driver.deleteMany('tasks', [
  ['completed', '=', true],
  'and',
  ['completedAt', '<', thirtyDaysAgo.toISOString()]
]);

4. Monitor Storage Usage

// Check storage size
const size = driver.getSize();
console.log(`Storing ${size} records`);

// Estimate storage usage
const estimate = navigator.storage?.estimate();
if (estimate) {
  const { usage, quota } = await estimate;
  const percentUsed = (usage! / quota!) * 100;
  console.log(`Storage: ${percentUsed.toFixed(2)}% used`);
}

Migration Guide

From Memory Driver

// Before (data lost on refresh)
import { MemoryDriver } from '@objectql/driver-memory';
const driver = new MemoryDriver();

// After (data persists)
import { LocalStorageDriver } from '@objectql/driver-localstorage';
const driver = new LocalStorageDriver();

From IndexedDB

// LocalStorage is simpler but has lower capacity
// Use IndexedDB for > 10MB data

// Small data (< 5MB): Use LocalStorage
const driver = new LocalStorageDriver();

// Large data (> 5MB): Use IndexedDB (future driver)
// const driver = new IndexedDBDriver();

Browser Compatibility

The LocalStorage Driver works in all modern browsers:

  • ✅ Chrome 4+
  • ✅ Firefox 3.5+
  • ✅ Safari 4+
  • ✅ Edge (all versions)
  • ✅ Opera 10.5+

Troubleshooting

Storage Quota Exceeded

// Problem: localStorage is full
// Solution: Clear old data
await driver.clear();

// Or delete specific records
await driver.deleteMany('tasks', [
  ['archived', '=', true]
]);

Data Not Persisting

// Check if localStorage is available
if (typeof localStorage === 'undefined') {
  console.error('localStorage not available');
  // Fallback to MemoryDriver
}

// Check browser privacy mode
// Private/Incognito mode may have limitations

Slow Queries

// Problem: Too many records to scan
const all = await driver.find('tasks', {});  // Scans all records

// Solution: Add filters to reduce result set
const filtered = await driver.find('tasks', {
  filters: [['status', '=', 'active']],
  limit: 50
});

Related Documentation

License

MIT - Same as ObjectQL

Changelog

See CHANGELOG.md for version history.