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.');
}
};
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);
};
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
};
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);
};
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
};
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.
About Me
As a dedicated remote web developer, I specialize in crafting modern, scalable web applications with a focus on performance and user experience. My expertise spans across full-stack development, utilizing cutting-edge technologies and best practices to deliver tailored solutions for diverse client needs. I’m committed to creating responsive, dynamic websites that bring ideas to life. Explore my portfolio here to see my latest projects, and connect with me on LinkedIn to discuss how I can help bring your next project to fruition!
References:
MDN Web Docs - IndexedDB API
A comprehensive guide on how IndexedDB works, its API methods, and use cases.
MDN IndexedDB GuideGoogle Developers - IndexedDB
A detailed article covering best practices and use of IndexedDB for building offline-capable web apps.
Google Developers - IndexedDBW3C 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!