Advance JavaScript (DOM, BOM, Web API) / Web API

Client Storage - IndexedDB

🔋 IndexedDB

IndexedDB is a built-in browser database designed for storing large amounts of data on the client side.

Think of it as a powerful key–value storage system that can hold almost any JavaScript data type:

  • Numbers, strings, booleans

  • Objects, arrays

  • Dates, blobs, files, and more


❓ Why Use IndexedDB?

  • Enables your application to work offline by keeping data locally.

  • Ideal for storing large or complex datasets.

  • Automatically syncs with the server once the user is online again.

👉 Real-World Example

Google Docs uses IndexedDB to save your documents locally, letting you continue editing even without an internet connection.

Other Practical Use Cases

  • Note-taking apps

  • To-do list apps

  • Quiz or learning apps

  • Code editors

  • CMS or content-heavy tools


  • Top-level container.

  • One app usually has one database, but you can create more if needed.

  • A database contains object stores.

  • Similar to tables in SQL.

  • Stores records as key–value pairs.

  • Can also have indexes.

  • Help you search and query data quickly.

  • You create them on object stores.

  • Example: a "contacts" store may have indexes on email, first name, last name, etc.


♦️Basic IndexedDB concepts

The following briefly introduces the basic concepts in the IndexedDB :

IndexedDB databases store key-value pairs

  • Unlike localStorage and sessionStorage, the values stored in the IndexedDB can be complex structures like objects and blobs.

  • Keys can be the properties of these objects or binary objects.

  • For quick searching and sorting, you can create indexes using any property of the objects.


IndexedDB is transactional

  • Every read from and write to the IndexedDB databases happens in a transaction.

  • The transactional model ensures data integrity in case users open the web application in multiple tabs/windows and perform the read from and write to the same database.


IndexedDB API is mostly asynchronous

  • IndexedDB operations are asynchronous. They use DOM events to notify you when an operation completes and the result is available.


IndexedDB is a NoSQL system

  • The IndexedDB is a NoSQL system, meaning it uses queries that return a cursor, which then you can use to iterate through the result set.


IndexedDB follows the same-origin policy

  • An origin consists of the domain, protocol, and port of a URL where the code executes.

  • For example https://developer.mozilla.org :

  • The  https://developer.mozilla.org/en-US/docs ****and https://www.javascripttutorial.net/ are the same origin because they have the same domain, protocol, and port.

  • However, the http://developer.mozilla.org and https://developer.mozilla.orgaren’t the same origin since they have different protocols and ports :

https://developer.mozilla.org

http://developer.mozilla.org

Protocol

https

http

Port

443

80

  • IndexedDB adheres to the same-origin policy, meaning each origin has its own set of databases. One origin cannot access databases from another origin.


Here is a clean, simplified rephrased version with clear code examples for each basic IndexedDB operation:


🪜 Basic IndexedDB Operations

These are the core actions you’ll perform when working with IndexedDB:

  • Open a connection to a database

  • Add (insert) data into an object store

  • Read data from an object store

  • Iterate through records using a cursor

  • Delete data from an object store

Below are simple examples for each step.

let db;

const request = indexedDB.open("MyDatabase", 1);

request.onupgradeneeded = function (e) {
  db = e.target.result;

  // Create an object store only once (during upgrade)
  if (!db.objectStoreNames.contains("users")) {
    db.createObjectStore("users", { keyPath: "id" });
  }
};

request.onsuccess = function (e) {
  db = e.target.result;
  console.log("Database opened successfully");
};

request.onerror = function () {
  console.log("Failed to open database");
};
function addUser(user) {
  const tx = db.transaction("users", "readwrite");
  const store = tx.objectStore("users");

  store.add(user);

  tx.oncomplete = () => console.log("User added");
  tx.onerror = () => console.log("Error adding user");
}

addUser({ id: 1, name: "Alice", age: 25 });
function getUser(id) {
  const tx = db.transaction("users", "readonly");
  const store = tx.objectStore("users");

  const request = store.get(id);

  request.onsuccess = () => {
    console.log("User:", request.result);
  };
}

getUser(1);
function getAllUsers() {
  const tx = db.transaction("users", "readonly");
  const store = tx.objectStore("users");

  const cursorRequest = store.openCursor();

  cursorRequest.onsuccess = (e) => {
    const cursor = e.target.result;

    if (cursor) {
      console.log("Record:", cursor.value);
      cursor.continue(); // Move to the next record
    } else {
      console.log("No more records");
    }
  };
}

getAllUsers();
function deleteUser(id) {
  const tx = db.transaction("users", "readwrite");
  const store = tx.objectStore("users");

  store.delete(id);

  tx.oncomplete = () => console.log("User deleted");
}

deleteUser(1);