When building modern web applications, we often need to store large amounts of structured data on the client side (browser). IndexedDB is an advanced browser-based storage API that allows you to store complex data efficiently. This blog will walk you through the basics of IndexedDB, how it works, and provide practical code examples to get you started.
What is IndexedDB?
IndexedDB is a low-level NoSQL database that allows you to store and manage key-value pairs directly in the browser. Unlike localStorage, which only supports strings, IndexedDB lets you store more complex data types such as objects, arrays, binary data, and files.
Key Features of IndexedDB:
- Asynchronous operations: All actions are non-blocking, ensuring the browser does not freeze.
- Transactional database: Ensures that changes are either fully completed or rolled back if something fails.
- Indexes for fast searches: Data retrieval becomes much quicker with indexes.
- Offline-first support: Works seamlessly even when users are offline.
- Supports large data sizes: Stores gigabytes of data, far beyond localStorage’s 5MB limit.
How IndexedDB Works
IndexedDB stores data in key-value pairs, but unlike a simple key-value store, it offers advanced features such as object stores and indexes for structured data storage. The process follows an asynchronous event model, meaning all operations like creating a database, adding, retrieving, or deleting data happen asynchronously using callbacks or promises.
Here are the core components of IndexedDB:
- Database: Represents a collection of object stores.
- Object Store: Similar to a table in SQL, it stores key-value pairs.
- Transactions: Used to perform a set of operations (read/write) safely.
- Indexes: Provide fast lookup of data based on fields other than the primary key.
- KeyPath: A field or property used to uniquely identify each item in an object store.
Steps to Use IndexedDB: A Practical Example
We’ll now go through a working example to understand how to use IndexedDB.
Step 1: Opening or Creating a Database
The open()
function creates a new database or opens an existing one. You can specify a version number, which triggers an onupgradeneeded
event to allow schema changes.
const request = indexedDB.open('myDatabase', 1); // Opens the database with version 1
request.onupgradeneeded = function(event) {
const db = event.target.result;
// Create an object store named 'notes' with 'id' as the key
db.createObjectStore('notes', { keyPath: 'id' });
};
request.onsuccess = function(event) {
console.log('Database opened successfully');
};
request.onerror = function(event) {
console.error('Error opening database:', event.target.error);
};
Step 2: Adding Data to IndexedDB
We can store data in an object store by creating a readwrite transaction.
function addNote(note) {
const request = indexedDB.open('myDatabase', 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction('notes', 'readwrite');
const store = transaction.objectStore('notes');
store.add(note); // Add the note to the object store
transaction.oncomplete = () => console.log('Note added successfully');
transaction.onerror = () => console.error('Failed to add note');
};
}
// Adding a note with id = 1
addNote({ id: 1, title: 'Learn IndexedDB', content: 'IndexedDB allows client-side storage' });
Step 3: Retrieving Data from IndexedDB
Use a readonly transaction to fetch data.
function getNoteById(id) {
const request = indexedDB.open('myDatabase', 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction('notes', 'readonly');
const store = transaction.objectStore('notes');
const getRequest = store.get(id);
getRequest.onsuccess = function() {
console.log('Retrieved Note:', getRequest.result);
};
getRequest.onerror = function() {
console.error('Failed to retrieve note');
};
};
}
// Retrieve the note with id = 1
getNoteById(1);
Step 4: Updating Data in IndexedDB
To update data, use the put()
method, which adds the item if it doesn't exist or updates it if it does.
function updateNote(note) {
const request = indexedDB.open('myDatabase', 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction('notes', 'readwrite');
const store = transaction.objectStore('notes');
store.put(note); // Updates the note
transaction.oncomplete = () => console.log('Note updated successfully');
transaction.onerror = () => console.error('Failed to update note');
};
}
// Update the note with id = 1
updateNote({ id: 1, title: 'Updated IndexedDB Note', content: 'Now with updated content!' });
Step 5: Deleting Data from IndexedDB
Use the delete()
method to remove data from an object store.
function deleteNoteById(id) {
const request = indexedDB.open('myDatabase', 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction('notes', 'readwrite');
const store = transaction.objectStore('notes');
store.delete(id); // Deletes the note with the given id
transaction.oncomplete = () => console.log('Note deleted');
transaction.onerror = () => console.error('Failed to delete note');
};
}
// Delete the note with id = 1
deleteNoteById(1);
Error Handling in IndexedDB
IndexedDB operations can fail, especially due to version mismatches or unauthorized access. Make sure to handle errors properly.
request.onerror = function(event) {
console.error('Database error:', event.target.error);
};
When to Use IndexedDB
- Storing large datasets: IndexedDB is perfect for data-intensive applications.
- Complex data management: Store arrays, objects, and binary data.
- Offline-first apps: It enables apps to function even without an internet connection.
- Need for fast data search: Use indexes to search quickly.
Browser Support for IndexedDB
IndexedDB is supported in most modern browsers, including Chrome, Firefox, Safari, Edge, and Opera. It works well for both desktop and mobile applications.
Conclusion
IndexedDB is a powerful storage API that offers advanced features for storing and managing large, structured data directly in the browser. Its asynchronous operations, transactional support, and indexing capabilities make it an essential tool for building data-intensive web applications, especially those that need to work offline.
By understanding the basics covered in this guide and experimenting with the provided code examples, you can start incorporating IndexedDB into your web projects today!