{"id":35659131,"url":"https://github.com/ts-collection/use-idb-storage","last_synced_at":"2026-01-16T23:03:30.706Z","repository":{"id":328978113,"uuid":"1111575219","full_name":"ts-collection/use-idb-storage","owner":"ts-collection","description":"A React hook for IndexedDB state management with automatic persistence, similar to useState but with data persistence across sessions.","archived":false,"fork":false,"pushed_at":"2026-01-15T13:54:05.000Z","size":322,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-15T17:47:19.821Z","etag":null,"topics":["hooks","idb","indexeddb","npm-package","react","typescript"],"latest_commit_sha":null,"homepage":"https://idb-play.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ts-collection.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-07T08:07:18.000Z","updated_at":"2026-01-15T13:54:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ts-collection/use-idb-storage","commit_stats":null,"previous_names":["sohanemon/idb","ts-collection/use-idb-storage"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/ts-collection/use-idb-storage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ts-collection%2Fuse-idb-storage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ts-collection%2Fuse-idb-storage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ts-collection%2Fuse-idb-storage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ts-collection%2Fuse-idb-storage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ts-collection","download_url":"https://codeload.github.com/ts-collection/use-idb-storage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ts-collection%2Fuse-idb-storage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28487106,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T22:54:02.790Z","status":"ssl_error","status_checked_at":"2026-01-16T22:50:10.344Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hooks","idb","indexeddb","npm-package","react","typescript"],"created_at":"2026-01-05T16:12:37.928Z","updated_at":"2026-01-16T23:03:30.688Z","avatar_url":"https://github.com/ts-collection.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# useIDBStorage\n\n[![npm](https://img.shields.io/npm/v/use-idb-storage)](https://www.npmjs.com/package/use-idb-storage)\n[![npm downloads](https://img.shields.io/npm/dm/use-idb-storage)](https://www.npmjs.com/package/use-idb-storage)\n![License](https://img.shields.io/npm/l/use-idb-storage)\n![Tests](https://github.com/sohanemon/idb/actions/workflows/test.yml/badge.svg)\n\nA React hook for IndexedDB state management with automatic persistence, similar to `useState` but with data persistence across sessions.\n\n## Performance\n\nNear-native performance with minimal overhead. Benchmark shows only 1.5ms difference vs `useState` for 400 forced updates:\n\n```json\n{\n  \"useState\": { \"renders\": 400, \"time\": 3317.9 },\n  \"useIDBStorage\": { \"renders\": 400, \"time\": 3316.4 },\n  \"differenceMs\": 1.5\n}\n```\n\nSee [PERFORMANCE.md](./PERFORMANCE.md) for detailed benchmarks.\n\n## Installation\n\n```bash\nnpm install use-idb-storage\n```\n\n## Quick Start\n\n### Basic Usage\n\n```tsx\nimport { useIDBStorage } from 'use-idb-storage';\n\nfunction MyComponent() {\n  const [user, setUser, removeUser] = useIDBStorage({\n    key: 'current-user',\n    defaultValue: { name: '', email: '' }\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        value={user.name}\n        onChange={e =\u003e setUser({ ...user, name: e.target.value })}\n      /\u003e\n      \u003cbutton onClick={() =\u003e removeUser()}\u003eClear\u003c/button\u003e\n      \u003cp\u003eData persists across browser sessions.\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Advanced Usage\n\nUse object destructuring for additional features:\n\n```tsx\nfunction AdvancedComponent() {\n  const {\n    data: user,\n    update: setUser,\n    reset: clearUser,\n    loading,\n    persisted,\n    error,\n    lastUpdated,\n    refresh\n  } = useIDBStorage({\n    key: 'current-user',\n    defaultValue: { name: '', email: '', avatar: null }\n  });\n\n  if (loading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\n  if (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003e{user.name || 'Anonymous'}\u003c/h2\u003e\n      \u003cbutton onClick={() =\u003e setUser(prev =\u003e ({\n        ...prev,\n        loginCount: (prev.loginCount || 0) + 1\n      }))}\u003e\n        Increment Login Count\n      \u003c/button\u003e\n      \u003cbutton onClick={() =\u003e setUser({ ...user, name: 'John' })}\u003e\n        Set Name\n      \u003c/button\u003e\n      \u003cbutton onClick={clearUser}\u003eReset\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e refresh()}\u003eRefresh from DB\u003c/button\u003e\n      \u003cdiv\u003e\n        Status: {persisted ? 'Saved' : 'Saving...'}\n        {lastUpdated \u0026\u0026 (\n          \u003cspan\u003eLast saved: {lastUpdated.toLocaleTimeString()}\u003c/span\u003e\n        )}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Global Configuration\n\nConfigure global defaults that affect all hooks and the exported `idb` instance:\n\n```tsx\nimport { configureIDBStorage, useIDBStorage, idb } from 'use-idb-storage';\n\n// Set global configuration\nconfigureIDBStorage({\n  database: 'my-app',\n  version: 1,\n  store: 'data'\n});\n\n// Hooks automatically use global config\nfunction MyComponent() {\n  const [user] = useIDBStorage({\n    key: 'current-user',\n    defaultValue: { name: '' }\n  }); // Uses global config: database=\"my-app\", store=\"data\"\n\n  // Override specific settings\n  const [cache] = useIDBStorage({\n    key: 'api-cache',\n    defaultValue: {},\n    store: 'cache' // Overrides global store\n  }); // Uses: database=\"my-app\", store=\"cache\"\n\n  return \u003cdiv\u003e...\u003c/div\u003e;\n}\n\n// The exported instance also uses global config\nasync function saveGlobalData() {\n  const store = await idb.store; // Uses global config\n  await store.set('global-key', 'global-value');\n}\n```\n\n### Global Configuration (No Context Required)\n\n```tsx\nimport { configureIDBStorage, idb } from 'use-idb-storage';\n\n// Configure global defaults\nconfigureIDBStorage({\n  database: 'my-app',\n  version: 1,\n  store: 'data'\n});\n\n// Use the pre-configured instance\nasync function saveUser(userData) {\n  const store = await idb.store;\n  await store.set('current-user', userData);\n}\n\nasync function getUser() {\n  const store = await idb.store;\n  return await store.get('current-user');\n}\n```\n\n### Advanced Usage\n\nUse object destructuring for additional features:\n\n```tsx\nfunction AdvancedComponent() {\n  const {\n    data: user,\n    update: setUser,\n    reset: clearUser,\n    loading,\n    persisted,\n    error,\n    lastUpdated,\n    refresh\n  } = useIDBStorage({\n    key: 'user-profile',\n    defaultValue: { name: '', email: '', avatar: null }\n  });\n\n  if (loading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\n  if (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003e{user.name || 'Anonymous'}\u003c/h2\u003e\n      \u003cbutton onClick={() =\u003e setUser(prev =\u003e ({\n        ...prev,\n        loginCount: (prev.loginCount || 0) + 1\n      }))}\u003e\n        Increment Login Count\n      \u003c/button\u003e\n      \u003cbutton onClick={() =\u003e setUser({ ...user, name: 'John' })}\u003e\n        Set Name\n      \u003c/button\u003e\n      \u003cbutton onClick={clearUser}\u003eReset\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e refresh()}\u003eRefresh from DB\u003c/button\u003e\n      \u003cdiv\u003e\n        Status: {persisted ? 'Saved' : 'Saving...'}\n        {lastUpdated \u0026\u0026 (\n          \u003cspan\u003eLast saved: {lastUpdated.toLocaleTimeString()}\u003c/span\u003e\n        )}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Class-based API\n\n```tsx\nimport { IDBStorage } from 'use-idb-storage';\n\nconst db = new IDBStorage({\n  database: 'my-app',\n  version: 1,\n  store: 'data'\n});\n\nconst store = await db.get('my-store');\nconst defaultStore = await db.store;\n\nawait store.set('user', { name: 'John', age: 30 });\nconst user = await store.get('user');\nawait store.delete('user');\n\nawait store.setMany([\n  ['key1', 'value1'],\n  ['key2', 'value2']\n]);\nconst values = await store.getMany(['key1', 'key2']);\n\nawait store.update('counter', (val) =\u003e (val || 0) + 1);\nconst allKeys = await store.keys();\nawait store.clear();\n```\n\n## API Reference\n\n### Default Instance\n\n```typescript\nimport { idb } from 'use-idb-storage';\n```\n\nA pre-configured `IDBStorage` instance using global defaults. Perfect for quick usage without setup.\n\n- `idb.store: Promise\u003cIDBStore\u003e` - Default store instance\n- `idb.get(storeName: string): Promise\u003cIDBStore\u003e` - Get a specific store\n- `idb.drop(storeName: string): Promise\u003cvoid\u003e` - Clear a store\n- `idb.close(): void` - Close the database connection\n\n#### Global Configuration\n\nConfigure global defaults that affect the default `idb` instance:\n\n```typescript\nimport { configureIDBStorage, idb } from 'use-idb-storage';\n\n// Set global configuration\nconfigureIDBStorage({\n  database: 'my-app',\n  version: 1,\n  store: 'data'\n});\n\n// Now idb.store refers to the 'data' store in 'my-app' database\nconst store = await idb.store;\nawait store.set('user', { name: 'John' });\n```\n\n### IDBStorage Class\n\nMain entry point for database operations.\n\n#### Constructor\n\n```typescript\nnew IDBStorage(config: IDBConfigValues)\n```\n\n#### Properties\n\n- `store: Promise\u003cIDBStore\u003e` - Default store instance (convenience getter)\n\n#### Methods\n\n- `get(storeName: string): Promise\u003cIDBStore\u003e` - Get a store instance\n- `getStore(): Promise\u003cIDBStore\u003e` - Get the default store instance\n- `drop(storeName: string): Promise\u003cvoid\u003e` - Clear a store (IndexedDB doesn't support dropping stores after creation)\n- `close(): void` - Close the database connection\n\n### IDBStore Class\n\nProvides operations for a specific object store.\n\n#### Methods\n\n**Single Operations:**\n- `get\u003cT\u003e(key: string): Promise\u003cT | undefined\u003e`\n- `set\u003cT\u003e(key: string, value: T): Promise\u003cvoid\u003e`\n- `delete(key: string): Promise\u003cvoid\u003e`\n\n**Batch Operations:**\n- `getMany\u003cT\u003e(keys: string[]): Promise\u003c(T | undefined)[]\u003e`\n- `setMany\u003cT\u003e(entries: [string, T][]): Promise\u003cvoid\u003e`\n- `deleteMany(keys: string[]): Promise\u003cvoid\u003e`\n\n**Utility Operations:**\n- `update\u003cT\u003e(key: string, updater: (value: T | undefined) =\u003e T): Promise\u003cvoid\u003e`\n- `clear(): Promise\u003cvoid\u003e`\n- `keys(): Promise\u003cstring[]\u003e`\n- `values\u003cT\u003e(): Promise\u003cT[]\u003e`\n- `entries\u003cT\u003e(): Promise\u003c[string, T][]\u003e`\n\n### useIDBStorage Hook\n\nSupports both simple `useState`-style usage and advanced object destructuring.\n\n#### Basic Usage\n\n```tsx\nconst [value, setValue, removeValue] = useIDBStorage({\n  key: 'my-key',\n  defaultValue: 'default value'\n});\n\nsetValue('new value');\nsetValue(prev =\u003e prev + ' updated');\nremoveValue();\n```\n\n#### Advanced Usage\n\n```tsx\nconst {\n  data,\n  update,\n  reset,\n  loading,\n  persisted,\n  error,\n  lastUpdated,\n  refresh\n} = useIDBStorage({\n  key: 'my-key',\n  defaultValue: 'default value'\n});\n```\n\n#### Parameters\n\n```typescript\ninterface IDBStorageOptions\u003cT\u003e {\n  key: string;              // Unique key for the stored value\n  defaultValue: T;          // Default value if none exists in IndexedDB\n  database?: string;        // Database name (uses context default)\n  version?: number;         // Database version (uses context default)\n  store?: string;           // Object store name (uses context default)\n}\n```\n\n#### Return Types\n\n**Tuple Destructuring** (useState-compatible):\n```typescript\n[value: T, setValue: (value: T | ((prev: T) =\u003e T)) =\u003e void, removeValue: () =\u003e void]\n```\n\n**Object Destructuring** (Full-featured):\n```typescript\n{\n  data: T,                                    // The stored data\n  update: (value: T | ((prev: T) =\u003e T)) =\u003e void, // Update function\n  reset: () =\u003e void,                          // Reset to default\n  loading: boolean,                           // Loading state\n  persisted: boolean,                         // Persistence status\n  error: Error | null,                        // Error state\n  lastUpdated: Date | null,                   // Last update timestamp\n  refresh: () =\u003e Promise\u003cvoid\u003e                // Force refresh from DB\n}\n```\n\n### Global Configuration\n\nConfigure global defaults for all hooks and the exported `idb` instance:\n\n```typescript\nimport { configureIDBStorage } from 'use-idb-storage';\n\nconfigureIDBStorage({\n  database: 'my-app',\n  version: 1,\n  store: 'data'\n});\n```\n\nThis sets the global defaults that are used by:\n- All `useIDBStorage` hooks (unless explicitly overridden)\n- The exported `idb` instance\n\n### Configuration\n\n```typescript\ninterface IDBConfigValues {\n  database: string;    // IndexedDB database name\n  version?: number;    // Database version (default: 1)\n  store: string;       // Default object store name\n}\n\n// Configure global defaults\nconfigureIDBStorage({\n  database: 'my-app',\n  version: 1,\n  store: 'data'\n});\n```\n\n## Examples\n\n### User Authentication\n\n```tsx\nfunction AuthProvider({ children }) {\n  const { data: user, update: setUser, reset: logout, loading } = useIDBStorage({\n    key: 'auth-user',\n    defaultValue: null\n  });\n\n  const login = async (credentials) =\u003e {\n    try {\n      const userData = await api.login(credentials);\n      setUser(userData);\n    } catch (error) {\n      console.error('Login failed:', error);\n    }\n  };\n\n  if (loading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\n\n  return (\n    \u003cAuthContext.Provider value={{ user, login, logout }}\u003e\n      {children}\n    \u003c/AuthContext.Provider\u003e\n  );\n}\n```\n\n### Shopping Cart\n\n```tsx\nfunction ShoppingCart() {\n  const {\n    data: cart,\n    update: updateCart,\n    reset: clearCart,\n    persisted,\n    lastUpdated\n  } = useIDBStorage({\n    key: 'shopping-cart',\n    defaultValue: { items: [], total: 0 }\n  });\n\n  const addItem = (item) =\u003e {\n    updateCart(prev =\u003e ({\n      items: [...prev.items, item],\n      total: prev.total + item.price\n    }));\n  };\n\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003eCart ({cart.items.length} items)\u003c/h2\u003e\n      {cart.items.map(item =\u003e (\n        \u003cdiv key={item.id}\u003e{item.name} - ${item.price}\u003c/div\u003e\n      ))}\n      \u003cp\u003eTotal: ${cart.total}\u003c/p\u003e\n      \u003cbutton onClick={clearCart}\u003eClear Cart\u003c/button\u003e\n      \u003cdiv\u003e\n        Status: {persisted ? 'Saved' : 'Saving...'}\n        {lastUpdated \u0026\u0026 \u003cspan\u003e • Saved {lastUpdated.toLocaleTimeString()}\u003c/span\u003e}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Auto-Save Form\n\n```tsx\nfunction AutoSaveForm() {\n  const {\n    data: formData,\n    update: updateForm,\n    loading,\n    error,\n    lastUpdated\n  } = useIDBStorage({\n    key: 'draft-form',\n    defaultValue: { title: '', content: '', tags: [] }\n  });\n\n  React.useEffect(() =\u003e {\n    const timer = setTimeout(() =\u003e {\n      console.log('Auto-saved at', new Date().toLocaleTimeString());\n    }, 1000);\n\n    return () =\u003e clearTimeout(timer);\n  }, [formData]);\n\n  if (loading) return \u003cdiv\u003eLoading draft...\u003c/div\u003e;\n  if (error) return \u003cdiv\u003eFailed to load draft: {error.message}\u003c/div\u003e;\n\n  return (\n    \u003cform\u003e\n      \u003cinput\n        value={formData.title}\n        onChange={e =\u003e updateForm(prev =\u003e ({ ...prev, title: e.target.value }))}\n        placeholder=\"Title\"\n      /\u003e\n      \u003ctextarea\n        value={formData.content}\n        onChange={e =\u003e updateForm(prev =\u003e ({ ...prev, content: e.target.value }))}\n        placeholder=\"Content\"\n      /\u003e\n      \u003cdiv\u003e\n        {lastUpdated \u0026\u0026 (\n          \u003csmall\u003eLast saved: {lastUpdated.toLocaleTimeString()}\u003c/small\u003e\n        )}\n      \u003c/div\u003e\n    \u003c/form\u003e\n  );\n}\n```\n\n### Error Handling\n\n```tsx\nfunction RobustComponent() {\n  const {\n    data: settings,\n    update: updateSettings,\n    reset: resetSettings,\n    error,\n    refresh,\n    loading\n  } = useIDBStorage({\n    key: 'user-settings',\n    defaultValue: { theme: 'light', notifications: true }\n  });\n\n  if (error) {\n    return (\n      \u003cdiv\u003e\n        \u003cp\u003eFailed to load settings: {error.message}\u003c/p\u003e\n        \u003cbutton onClick={() =\u003e refresh()}\u003eRetry\u003c/button\u003e\n        \u003cbutton onClick={resetSettings}\u003eReset to Defaults\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n\n  if (loading) return \u003cdiv\u003eLoading settings...\u003c/div\u003e;\n\n  return (\n    \u003cdiv\u003e\n      \u003clabel\u003e\n        Theme:\n        \u003cselect\n          value={settings.theme}\n          onChange={e =\u003e updateSettings(prev =\u003e ({\n            ...prev,\n            theme: e.target.value\n          }))}\n        \u003e\n          \u003coption value=\"light\"\u003eLight\u003c/option\u003e\n          \u003coption value=\"dark\"\u003eDark\u003c/option\u003e\n        \u003c/select\u003e\n      \u003c/label\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## Advanced Usage\n\n### Custom Configuration\n\n```tsx\nimport { configureIDBStorage, useIDBStorage, idb } from 'use-idb-storage';\n\n// Configure global defaults\nconfigureIDBStorage({\n  database: 'my-app',\n  version: 2,\n  store: 'data'\n});\n\nfunction MyComponents() {\n  // Uses global config: database=\"my-app\", store=\"data\"\n  const [user] = useIDBStorage({\n    key: 'user',\n    defaultValue: { name: '' }\n  });\n\n  // Overrides store: database=\"my-app\", store=\"cache\"\n  const [cache] = useIDBStorage({\n    key: 'api-cache',\n    defaultValue: {},\n    store: 'cache'\n  });\n\n  // Uses global config: database=\"my-app\", store=\"data\"\n  const saveToGlobalStore = async () =\u003e {\n    const store = await idb.store;\n    await store.set('global-key', 'global-value');\n  };\n\n  return \u003cdiv\u003e...\u003c/div\u003e;\n}\n```\n\n### Migration\n\nIncrement version for schema changes:\n\n```tsx\n\u003cIDBConfig database=\"my-app\" version={1} store=\"data\"\u003e\n  \u003cApp /\u003e\n\u003c/IDBConfig\u003e\n\n\u003cIDBConfig database=\"my-app\" version={2} store=\"data\"\u003e\n  \u003cApp /\u003e\n\u003c/IDBConfig\u003e\n```\n\n### Class-based API\n\n```tsx\nimport { IDBStorage } from 'use-idb-storage';\n\nconst db = new IDBStorage({ database: 'my-app' });\nconst store = await db.get('analytics');\n\nawait store.setMany([\n  ['pageviews', 1234],\n  ['sessions', 89],\n  ['bounce-rate', 0.45]\n]);\n\nconst allKeys = await store.keys();\nconst allData = await store.values();\n```\n\n\n\n## 🌐 Browser Support\n\n- Chrome 24+\n- Firefox 16+\n- Safari 10+\n- Edge 12+\n\n## 📄 License\n\nISC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fts-collection%2Fuse-idb-storage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fts-collection%2Fuse-idb-storage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fts-collection%2Fuse-idb-storage/lists"}