Databases

    Description — Working with Couchbase Lite Databases in JavaScript
    Related Content — Encryption | Blobs | Documents | Indexing

    Database Concepts

    Databases created on Couchbase Lite can share the same hierarchical structure as Capella databases. This makes it easier to sync data between browser applications and applications built using Capella.

    Couchbase Lite Database Hierarchy
    Figure 1. Couchbase Lite Database Hierarchy

    Although the terminology is different, the structure can be mapped to relational database terms:

    Table 1. Relational Database → Couchbase
    Relational database Couchbase

    Database

    Database

    Schema

    Scope

    Table

    Collection

    This structure gives you plenty of choices when it comes to partitioning your data. The most basic structure is to use the single default scope with a single default collection; or you could opt for a structure that allows you to split your collections into logical scopes.

    Couchbase Lite Examples
    Figure 2. Couchbase Lite Examples
    Storing local configuration

    You may not need to sync all the data related for a particular application. You can set up a scope that syncs data, and a second scope that doesn’t.

    One reason for doing this is to store local configuration data (such as user preferences or UI state). Since this information only relates to a particular browser or device, there is no need to sync it:

    local data scope

    Contains information pertaining to the browser or device.

    syncing data scope

    Contains information pertaining to the user, which can be synced back to the cloud for use on the web or another device.

    Browser Storage

    Couchbase Lite JavaScript stores data in the browser’s IndexedDB, a robust client-side storage API.

    IndexedDB Characteristics
    • Stores data persistently across browser sessions

    • Subject to browser storage quotas

    • Data is scoped per origin (protocol + domain + port)

    • Supports concurrent access from multiple browser tabs

    • May be evicted under storage pressure on some browsers

    Create or Open Database

    You can create a new database and-or open an existing database, using the Database class. Pass in a database name and a DatabaseConfig — see Example 1.

    Things to watch for include:

    • If the named database does not exist, a new one is created

    • The database is stored in the browser’s IndexedDB under the current origin

    Unlike native Couchbase Lite SDKs, collections and their indexes must be declared in the DatabaseConfig when opening the database. Collections cannot be created or deleted while the database is open.
    Example 1. Open or create a database
    const config: DatabaseConfig<AppSchema> = {
        name: 'myapp',
        version: 1,
        collections: {
            tasks: {},
            users: {}
        }
    };
    const database = await Database.open(config);
    console.log('Database opened:', database.name);
    1 Database configuration with name and version
    2 Collections configuration (required)
    3 Open the database

    Database Configuration

    The DatabaseConfig interface provides options for configuring your database:

    Property Type Description

    collections

    CollectionsConfig

    Declares all collections and their configurations. Required.

    password

    string

    Encryption password for database encryption at rest. See Database Encryption. Optional.

    Collections Configuration

    Each collection can have its own configuration within the collections object:

    Property Type Description

    indexes

    string[]

    Index properties for the collection. Indexed properties are not encrypted when database encryption is enabled. See Indexing and Database Encryption. Optional.

    Example 2. Configure database with encryption
    const encryptedConfig: DatabaseConfig = {
        name: 'secure-app', (1)
        version: 1,
        password: 'my-secure-password', (2)
        collections: {
            users: {
                indexes: ['username', 'email'] (3)
            }
        }
    };
    
    const secureDb = await Database.open(encryptedConfig);
    1 Database name and version
    2 Encryption password
    3 Unencrypted properties (can be indexed)

    Close Database

    You are advised to incorporate the closing of all open databases into your application workflow.

    To close a database, use Database.close() — see: Example 3. This also closes active replications, listeners and-or live queries connected to the database.

    Closing a database soon after starting a replication involving it can cause an exception as the asynchronous replicator may not yet be connected.
    Safely Closing a Database
    Before closing, check that any attached listeners (query/replication/change) indicate they are at least at connected status before closing — see for example: Monitor Status.
    Example 3. Close a Database
    database.close();
    console.log('Database closed');

    Reopen Database

    After closing a database, you can reopen it using the same configuration. If the database was encrypted, you must provide the password when reopening the database — see Database Encryption for more information.

    Database Encryption

    Couchbase Lite JavaScript supports encrypting databases stored in IndexedDB to secure data at rest.

    For complete information on database encryption, including how to enable encryption, manage encryption keys, and understand encryption limitations in browser environments, see Database Encryption.

    Delete Database

    To permanently delete a database and all its data from IndexedDB:

    Example 4. Delete a database
    // Close the database first
    database.close();
    
    // Delete the database
    await Database.delete('myapp');
    
    console.log('Database deleted');
    Deleting a database is permanent and cannot be undone. All data, collections, and indexes are removed from IndexedDB.

    Multiple Databases

    An application can open and use multiple databases simultaneously. Each database is stored separately in IndexedDB.

    Example 5. Using multiple databases
    // Open multiple databases
    const userDb = await Database.open('users', {
      collections: { profiles: {} }
    });
    
    const contentDb = await Database.open('content', {
      collections: { articles: {}, comments: {} }
    });
    
    const localDb = await Database.open('local-config', {
      collections: { settings: {} }
    });
    
    // Use them independently
    await userDb.collection.profiles.save({...});
    await contentDb.collection.articles.save({...});
    
    // Close when done
    await userDb.close();
    await contentDb.close();
    await localDb.close();

    Storage Management

    Databases in Couchbase Lite JavaScript are subject to browser storage quotas and policies.

    IndexedDB quotas, persistence, and eviction rules vary by browser, so the same app may store different amounts of data across environments. When writes exceed quota, a QuotaExceededError is thrown with no automatic retry or cleanup. The application must catch these errors, decide how to free space, or prompt the user. The SDK relies entirely on IndexedDB’s native behavior. See Browsers and Storage for detailed information.

    Storage Quotas

    Browsers enforce storage quotas that vary by platform:

    • Desktop browsers: Typically 10% of available disk space

    • Mobile browsers: Typically 50-100 MB

    • Private browsing: Limited or no persistent storage

    For detailed storage limits by browser, see Browser-Specific Considerations.

    The SDK provides APIs to check available storage:

    Example 6. Check storage quota
    if (navigator.storage && navigator.storage.estimate) {
      const estimate = await navigator.storage.estimate();
    
      console.log('Quota:', estimate.quota);
      console.log('Usage:', estimate.usage);
      console.log('Available:', estimate.quota - estimate.usage);
    
      const percentUsed = (estimate.usage / estimate.quota) * 100;
      console.log(`Storage: ${percentUsed.toFixed(2)}% used`);
    }

    Request Persistent Storage

    To reduce the risk of storage eviction, request persistent storage:

    Example 7. Request persistent storage
    if (navigator.storage && navigator.storage.persist) {
      const isPersistent = await navigator.storage.persist();
    
      if (isPersistent) {
        console.log('Persistent storage granted');
      } else {
        console.log('Persistent storage not granted');
      }
    }

    Database Maintenance

    From time to time it may be necessary to perform maintenance on your database, such as compacting the database to remove unused documents and blobs.

    Couchbase Lite’s API provides the Database.performMaintenance() method. The available maintenance operations include compact, reindex, and integrityCheck.

    This is a resource-intensive operation and is not performed automatically. It should be run on-demand using the API.

    Example 8. Compact a database
    // Compact the database to reclaim space
    await database.performMaintenance('compact');
    
    console.log('Database compacted');

    Inspect Database

    You can inspect the contents of your database using browser developer tools.

    Using Browser DevTools

    To view your database in IndexedDB:

    1. Open browser DevTools (F12 or Cmd/Ctrl+Shift+I)

    2. Go to the Application tab (Chrome) or Storage tab (Firefox)

    3. Expand IndexedDB in the sidebar

    4. Find your database by name

    5. Explore collections and documents

    Browser DevTools
    • Chrome DevTools: Application > Storage > IndexedDB

    • Firefox DevTools: Storage > IndexedDB

    • Safari DevTools: Storage > IndexedDB (Enable Develop menu first)

    • Edge DevTools: Application > Storage > IndexedDB

    Change Listeners

    IndexedDB allows concurrent reading from multiple tabs. Write operations are serialized per store/transaction, not per tab. IndexedDB does not have built-in cross-tab change notifications; these must be implemented by the SDK or the app.

    The SDK provides two types of change listeners, depending on the granularity your application needs:

    Collection Change Listeners

    • Trigger whenever any document in the collection changes

    • Useful for keeping UI or state synchronized broadly

    Example 9. Collection Change Listener Example
    const collection = database.collection.tasks;
    
    // Fires when any document in the collection changes
    const token = collection.addChangeListener((changes) => {
      console.log("Changed docs:", changes.documentIDs);
      refreshUI();
    });
    
    // Remove listener when done
    collection.removeChangeListener(token);

    Document Change Listeners

    • Trigger only when a specific document changes

    • Useful when you want focused updates without scanning the whole collection

    Example 10. Document Change Listener Example
    const collection = database.collection.tasks;
    const docId = "task_001";
    
    // Fires only when the given document changes
    const token = collection.addDocumentChangeListener(docId, (change) => {
      console.log("Document updated:", change.documentID);
      updateTaskView(docId);
    });
    
    // Remove listener when done
    collection.removeDocumentChangeListener(token);

    Troubleshooting

    You should use browser console logs as your first source of diagnostic information. If the information in the default logging level is insufficient, you can focus it on database errors and generate more verbose messages — see: Example 11.

    For more on using Couchbase logs — see: Using Logs.

    Example 11. Increase level of database log messages
    import { configure, getConsoleSink } from '@logtape/logtape';
    import { LogCategory } from '@couchbase/lite-js';
    
    // Configure logging for database operations
    await configure({
      sinks: {
        console: getConsoleSink(),
      },
      loggers: [
        {
          category: [LogCategory, 'DB'],
          lowestLevel: 'debug',
          sinks: ['console'],
        }
      ],
    });

    Common Issues

    QuotaExceededError

    Problem: Database operations fail with QuotaExceededError

    Solutions:

    • Request persistent storage

    • Reduce data size

    • Compact the database

    • Delete unnecessary documents

    See troubleshooting-storage.adoc for more solutions.

    EncryptionError

    Problem: Database fails to open with encryption error

    Solutions:

    • Verify the encryption password is correct

    • Check if database was encrypted in the first place

    • Ensure password is consistently provided

    Collections Not Accessible

    Problem: Cannot access collections after opening database

    Solutions:

    • Verify collections were declared in DatabaseConfig

    • Close and reopen database with correct configuration

    • Check collection names for typos