HTML IndexedDB Retrieve

Beginner
8 min read
Updated: Nov 2026
5 examples
Live preview

Definition and Usage

IndexedDB retrieve means reading records from an object store. Use IDBObjectStore.get(key) for one record, getAll() for an array of values, and openCursor() to walk records one by one.

Reads usually run in a readonly transaction (the default). After you insert data, retrieve it here, then update or delete as needed.

Baseline · Widely available.

Not deprecated. get() and openCursor() are stable since about July 2015. getAll() is widely available since about January 2020. Also available in Web Workers.

Quick rule.

Know the primary key? Use get(). Need everything (small store)? Use getAll(). Large store or custom filtering? Use openCursor(). Lookup by email/name? Use an index.

Syntax

syntax.js
store.get( key)
syntax.js
store.getAll( query?, count?)
syntax.js
store.openCursor( query?, direction?)

Related helpers: getAllKeys(), getKey(), count(), and store.index(name).get(value) for non-primary-key lookups.

Parameters

Common arguments for the main read methods:

ParameterUsed byDescription
key / queryget, getAll, openCursorA primary key or IDBKeyRange. For getAll/openCursor, omit it to select the whole store.
countgetAllOptional max number of values to return (0 to 232−1).
directionopenCursorOptional: next (default), prev, nextunique, or prevunique.

Return Value

All of these return an IDBRequest. On success:

Methodrequest.result
get(key)The record value, or undefined if missing
getAll()An Array of matching values
openCursor()An IDBCursorWithValue, or null when finished / no match
ExceptionWhen it is thrown
TransactionInactiveErrorThe transaction is no longer active
DataErrorInvalid key or key range
InvalidStateErrorThe object store was deleted

How It Works

A typical read follows these steps:

  1. Open the database with indexedDB.open(name, version).
  2. Start a read tx: db.transaction(['store'], 'readonly').
  3. Get the store: tx.objectStore('store').
  4. Call get, getAll, or openCursor.
  5. Use onsuccess to read request.result and update the UI.
JS
const tx = db.transaction(['contacts'], 'readonly');
const req = tx.objectStore('contacts').get(1);

req.onsuccess = () => {
  const contact = req.result;
  if (!contact) {
    console.log('Not found');
    return;
  }
  console.log(contact.name);
};

Live Preview

Seed sample contacts, then try get(), getAll(), and a cursor walk.

Uses a private demo database in this browser. Safe to click repeatedly.

Status

Opening database…

Examples

Short, copy-ready snippets. Use Try It Yourself for a live editor.

Example 1 — Read One Record with get()

Fetch the contact whose primary key is 1.

JS
const tx = db.transaction(['contacts'], 'readonly');
const req = tx.objectStore('contacts').get(1);

req.onsuccess = function () {
  const contact = req.result;
  if (!contact) {
    console.log('Contact not found');
    return;
  }
  console.log(contact.name, contact.email);
};
Try It Yourself

How It Works

  1. Open a readonly transaction on the store.
  2. Call get(1) with the primary key.
  3. Check for undefined—missing keys do not throw.
  4. Use the object from req.result in your UI.

Example 2 — Load All Records with getAll()

Return every value in the store as an array.

JS
const tx = db.transaction(['contacts'], 'readonly');
const req = tx.objectStore('contacts').getAll();

req.onsuccess = function () {
  const rows = req.result;
  console.log('Count:', rows.length);
  rows.forEach(function (c) {
    console.log(c.id, c.name);
  });
};
Try It Yourself

How It Works

  1. Call getAll() with no query to load the whole store.
  2. Optional: pass a key range and/or count to limit results.
  3. result is always an array (empty when nothing matches).
  4. Prefer a cursor for very large datasets.

Example 3 — Iterate with openCursor()

Walk each record and call continue() until the cursor is null.

JS
const tx = db.transaction(['contacts'], 'readonly');
const req = tx.objectStore('contacts').openCursor();

req.onsuccess = function () {
  const cursor = req.result;
  if (!cursor) {
    console.log('Done');
    return;
  }
  console.log(cursor.key, cursor.value.name);
  cursor.continue();
};
Try It Yourself

How It Works

  1. Open a cursor on the store (optionally with a range/direction).
  2. Read cursor.value for the current record.
  3. Call cursor.continue() to advance.
  4. Stop when result is null—no more matches.

Example 4 — Look Up by Index

Query a non-key field after creating an index in onupgradeneeded.

JS
/* earlier in onupgradeneeded:
   store.createIndex('by_email', 'email', { unique: true });
*/
const tx = db.transaction(['contacts'], 'readonly');
const index = tx.objectStore('contacts').index('by_email');
const req = index.get('[email protected]');

req.onsuccess = function () {
  const contact = req.result;
  if (!contact) {
    console.log('No match for that email');
    return;
  }
  console.log('Found:', contact.name);
};
Try It Yourself

How It Works

  1. Create the index once during a version upgrade.
  2. Open it with store.index('by_email').
  3. Call index.get(value) with the indexed field.
  4. Handle missing results the same way as store.get().

Example 5 — Complete HTML Page

Seed two contacts on load, then show one record when the user clicks.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>IndexedDB Retrieve Demo</title>
</head>
<body>
  <h1>IndexedDB Retrieve</h1>
  <button type="button" id="getBtn" disabled>Get contact id 1</button>
  <p id="status">Opening…</p>

  <script>
    let db;
    const openReq = indexedDB.open('retrieveDemoDb', 1);

    openReq.onupgradeneeded = function (event) {
      event.target.result.createObjectStore('contacts', { keyPath: 'id' });
    };

    openReq.onsuccess = function (event) {
      db = event.target.result;
      const tx = db.transaction(['contacts'], 'readwrite');
      const store = tx.objectStore('contacts');
      store.put({ id: 1, name: 'Alex Rivera', email: '[email protected]' });
      store.put({ id: 2, name: 'Sam Lee', email: '[email protected]' });
      tx.oncomplete = function () {
        document.getElementById('status').textContent = 'Ready.';
        document.getElementById('getBtn').disabled = false;
      };
    };

    document.getElementById('getBtn').addEventListener('click', function () {
      const tx = db.transaction(['contacts'], 'readonly');
      const req = tx.objectStore('contacts').get(1);
      req.onsuccess = function () {
        const c = req.result;
        document.getElementById('status').textContent = c
          ? c.name + ' <' + c.email + '>'
          : 'Not found';
      };
    });
  </script>
</body>
</html>
Try It Yourself

How It Works

  1. Create the store in onupgradeneeded.
  2. Seed sample rows after the database opens.
  3. On click, run get(1) in a readonly transaction.
  4. Show the result in a status paragraph for learners.

Edge Cases & Pitfalls

Most retrieve bugs come from treating missing keys as errors or loading too much with getAll().

missing

get() missing ≠ error

A missing key succeeds with undefined. Always check before reading properties.

ambiguous

Undefined value vs missing row

get() cannot tell these apart. Use openCursor(key) or count(key) when you must know if the key exists.

memory

getAll() loads everything

Fine for small stores. For large data, prefer openCursor() or a limited key range.

index

Indexes need an upgrade

createIndex() only works in onupgradeneeded. Calling index() for a missing name throws.

mode

Readonly is enough

Reads do not need readwrite. Keep write mode for insert/update/delete only.

Browser Support

IndexedDB get(), getAll(), and openCursor() are standard Web Storage features in modern browsers—not a Node.js, Deno, or Bun API.

✓ Baseline · Widely available

IndexedDB get() / getAll()

get() and openCursor() are widely available since about July 2015. getAll() is widely available since about January 2020 across Chrome, Firefox, Safari, Edge, and Opera.

96% Global support (approx.)
Google Chrome 24+
Full support
Mozilla Firefox 16+
Full support
Apple Safari 10+
Full support
Microsoft Edge 12+
Full support
Opera 15+
Full support
Samsung Internet 1.5+
Full support
Internet Explorer 10+
Partial / older
IndexedDB retrieve Widely supported

Bottom line: Safe to use IndexedDB reads in production web apps. Prefer feature detection with window.indexedDB for very old browsers.

Key Takeaways

  • One record: store.get(key) in a readonly transaction.
  • Many records: getAll() for arrays; openCursor() for large or streamed reads.
  • Missing keys: succeed with undefined—check before use.
  • Non-key fields: create an index, then store.index(name).get(value).

One line: read with get() / getAll() / openCursor() in a readonly transaction.

Frequently Asked Questions

Open the database with indexedDB.open(), start a readonly transaction: db.transaction(['storeName'], 'readonly'), get the object store, then call store.get(key) for one record or store.getAll() for every record. Handle the result in the request's onsuccess callback.
get(key) returns one record by primary key. openCursor() walks records one at a time—useful for large stores, filtering in JavaScript, or reading without loading every object into memory at once.
When no record matches the key, get() still succeeds but result is undefined. That is not an error. Check if (result) before using the data. Note: a stored undefined value looks the same—use openCursor(key) or count(key) if you must tell those apart.
Yes. Use db.transaction(['store'], 'readonly') for get(), getAll(), openCursor(), and count(). You can omit the mode (it defaults to readonly), but being explicit is clearer for beginners.
Create an index in onupgradeneeded with createIndex(), then use store.index('indexName').get(value) or openCursor() on that index to look up records by email, name, or other fields.
Use getAll() when you need an array of all matching values and the dataset is small enough to load at once. Prefer openCursor() for large stores or when you only need keys or selective filtering.

Next: IndexedDB Update

Change records you retrieved with get-modify-put patterns.

Update tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

10 people found this page helpful