DEV Community

Jeferson F Silva
Jeferson F Silva

Posted on

A Beginner's Guide to IndexedDB

A Tutorial on Using Client-Side Storage in Web Apps

When building modern web applications, especially progressive web apps (PWAs), it's crucial to have a way to store data offline. IndexedDB is a powerful client-side database that allows web apps to store and retrieve data, even when the user is offline. This guide will walk you through the basics of IndexedDB, showing you how to create, read, update, and delete data (CRUD operations) within your web app.

What is IndexedDB?

IndexedDB is a low-level API for client-side storage of large amounts of structured data, including files and blobs. Unlike localStorage, IndexedDB allows you to store complex data types, not just strings. It uses an asynchronous, transactional database model, which makes it powerful for applications needing to handle large datasets or offline data syncing.

Why Use IndexedDB?

  • Offline capabilities: Ideal for Progressive Web Apps (PWAs) and offline-first applications.
  • Storage capacity: IndexedDB can store far more data compared to localStorage (which is limited to about 5-10MB).
  • Flexibility: Store complex objects like arrays, objects, and even blobs.
  • Asynchronous: Operations do not block the UI thread, meaning your app remains responsive.

Getting Started: Setting Up IndexedDB

Let's dive into the core steps for working with IndexedDB. We will cover:

  • Creating or opening a database
  • Creating object stores (tables)
  • Adding data
  • Reading data
  • Updating data
  • Deleting data

Step 1: Opening a Database

To interact with IndexedDB, you first need to open a connection to the database. If the database doesn't exist, it will be created.

const request = indexedDB.open('MyCustomersDatabase', 1);

request.onerror = (event) => {
    console.error('Database error:', event.target.errorCode);
};

request.onsuccess = (event) => {
    const db = event.target.result;
    console.log('Database opened successfully', db);
};

request.onupgradeneeded = (event) => {
    const db = event.target.result;
    if (!db.objectStoreNames.contains('customers')) {
        const objectStore = db.createObjectStore('customers', { keyPath: 'id' });
        objectStore.createIndex('name', 'name', { unique: false });
        objectStore.createIndex('email', 'email', { unique: true });
        console.log('Object store created.');
    }
};
Enter fullscreen mode Exit fullscreen mode

Here’s what’s happening:

  • indexedDB.open opens or creates the database.
  • onerror handles any errors when opening the database.
  • onsuccess is triggered when the database connection is successfully opened.
  • onupgradeneeded is fired when the database needs to be upgraded (e.g., if this is the first time opening the database or if the version changes). It’s where you define your object stores (think of them as tables in SQL).

Step 2: Adding Data to IndexedDB

Now that we have our database and object store set up, let’s add some data to it.

const addCustomer = (db, customer) => {
    const transaction = db.transaction(['customers'], 'readwrite');
    const objectStore = transaction.objectStore('customers');
    const request = objectStore.add(customer);

    request.onsuccess = () => {
        console.log('Customer added:', customer);
    };

    request.onerror = (event) => {
        console.error('Error adding customer:', event.target.errorCode);
    };
}

const customer = { id: 1, name: 'John Doe', email: 'john@example.com' };

request.onsuccess = (event) => {
    const db = event.target.result;
    addCustomer(db, customer);
};
Enter fullscreen mode Exit fullscreen mode

Here’s what’s happening:

  • We create a transaction with 'readwrite' access to allow modifications.
  • The add() method is used to insert data into the object store.
  • We listen for success and error events to confirm whether the data was added successfully.

Step 3: Reading Data from IndexedDB

Reading data from IndexedDB is also straightforward. Let’s retrieve the customer we just added by using the get() method.

const getCustomer = (db, id) => {
    const transaction = db.transaction(['customers'], 'readonly');
    const objectStore = transaction.objectStore('customers');
    const request = objectStore.get(id);

    request.onsuccess = (event) => {
        const customer = event.target.result;
        if (customer) {
            console.log('Customer found:', customer);
        } else {
            console.log('Customer not found.');
        }
    };

    request.onerror = (event) => {
        console.error('Error fetching customer:', event.target.errorCode);
    };
}

request.onsuccess = (event) => {
    const db = event.target.result;
    getCustomer(db, 1); // Fetch customer with ID 1
};
Enter fullscreen mode Exit fullscreen mode

Step 4: Updating Data in IndexedDB

To update an existing record, we can use the put() method, which works similarly to add() but replaces the record if the key already exists.

const updateCustomer = (db, customer) => {
    const transaction = db.transaction(['customers'], 'readwrite');
    const objectStore = transaction.objectStore('customers');
    const request = objectStore.put(customer);

    request.onsuccess = () => {
        console.log('Customer updated:', customer);
    };

    request.onerror = (event) => {
        console.error('Error updating customer:', event.target.errorCode);
    };
}

const updatedCustomer = { id: 1, name: 'Jane Doe', email: 'jane@example.com' };

request.onsuccess = (event) => {
    const db = event.target.result;
    updateCustomer(db, updatedCustomer);
};
Enter fullscreen mode Exit fullscreen mode

Step 5: Deleting Data from IndexedDB

Finally, to delete a record, use the delete() method.

const deleteCustomer = (db, id) => {
    const transaction = db.transaction(['customers'], 'readwrite');
    const objectStore = transaction.objectStore('customers');
    const request = objectStore.delete(id);

    request.onsuccess = () => {
        console.log('Customer deleted.');
    };

    request.onerror = (event) => {
        console.error('Error deleting customer:', event.target.errorCode);
    };
}

request.onsuccess = (event) => {
    const db = event.target.result;
    deleteCustomer(db, 1); // Delete customer with ID 1
};
Enter fullscreen mode Exit fullscreen mode

Conclusion

IndexedDB is a robust solution for handling client-side data storage, especially in offline-first web apps. By following this guide, you’ve learned how to:

  • Open and create a database
  • Create object stores
  • Add, read, update, and delete data

With IndexedDB, you can build more resilient web applications that store data locally and work even without an internet connection.

References:

  1. MDN Web Docs - IndexedDB API

    A comprehensive guide on how IndexedDB works, its API methods, and use cases.

    MDN IndexedDB Guide

  2. Google Developers - IndexedDB

    A detailed article covering best practices and use of IndexedDB for building offline-capable web apps.

    Google Developers - IndexedDB

  3. W3C Indexed Database API

    The official specification from W3C outlining the technical implementation and structure of IndexedDB.

    W3C IndexedDB Spec

These resources will provide additional depth and context if you're looking to explore more about IndexedDB beyond this tutorial!

Happy coding!

Top comments (0)