Skip to content

Capabilities · API

Storage Buckets API

Published Updated

Limited availabilityNot supported in Firefox (Desktop), Safari (macOS)WICG draft

navigator.storageBuckets.open(name, options) creates or opens a named storage bucket: a partition of the origin’s storage with its own indexedDB factory, caches, bucket file system, persistence mode, quota ceiling, and expiry date, so the browser can evict a low-value bucket under storage pressure while leaving a persisted one intact. Without buckets an origin has a single default bucket and eviction is all-or-nothing.

Chrome 122 and Edge 122 ship StorageBucketManager and every StorageBucket member (indexedDB, caches, getDirectory(), persist(), estimate(), setExpires()) together; Chrome for Android, Samsung Internet, and Android WebView mirror that version. Firefox has not implemented it (Bugzilla 1594740) and Safari has no implementation (BCD api.StorageBucketManager). Treat buckets as an enhancement over the default bucket: a page that stores data in bucket.indexedDB on Chrome and in window.indexedDB elsewhere keeps the same schema code.

navigator.storageBuckets.open(name)
navigator.storageBuckets.open(name, options)
navigator.storageBuckets.keys()
navigator.storageBuckets.delete(name)
bucket.persist()
bucket.persisted()
bucket.estimate()
bucket.setExpires(timestamp)
bucket.expires()
bucket.getDirectory()

open() returns a Promise<StorageBucket>, keys() a Promise<sequence<DOMString>> of live bucket names, and delete() a Promise<undefined> that resolves even when no bucket of that name exists. navigator.storageBuckets is [SecureContext] and exposed on Window and workers; persist() is Window-only because it may consult the persistent-storage permission. The indexedDB and caches attributes are ordinary IDBFactory and CacheStorage objects scoped to the bucket, and getDirectory() returns a FileSystemDirectoryHandle for a bucket-scoped origin private file system.

open() takes a bucket name and an optional StorageBucketOptions dictionary. The name must be 1 to 64 code points of ASCII lowercase letters, digits, _, or -, and must not start with _ or -; opening an existing name returns the existing bucket and ignores options.

Member Type Required Description
persisted boolean No, defaults to false Request the "persistent" bucket mode. Granted only when the persistent-storage permission is "granted"; otherwise the bucket opens in best-effort mode and bucket.persisted() resolves false.
quota unsigned long long (bytes) No Upper bound for the bucket’s usage; the browser may enforce a lower one. bucket.estimate() reports it as quota when set.
expires DOMHighResTimeStamp (ms since the Unix epoch) No When the bucket is to be treated as gone. An expired bucket is removed lazily on the next open(), keys(), or access.

Chromium’s IDL also carries a durability member ("strict" or "relaxed") behind the StorageBucketsDurability runtime flag; the WICG explainer removed it from the first version of the API because IndexedDB transactions already expose the same durability option, so do not rely on it.

The StorageBucket returned by open() has these members.

Member Type Description
name DOMString (read-only) The key the bucket was opened with.
persist() Promise<boolean> Upgrades to "persistent" mode if the persistent-storage permission is already granted; resolves with the resulting mode.
persisted() Promise<boolean> true when the bucket is in "persistent" mode.
estimate() Promise<StorageEstimate> usage and quota for this bucket alone, unlike navigator.storage.estimate(), which covers the whole origin.
setExpires(ms) / expires() Promise<undefined> / Promise<DOMHighResTimeStamp?> Set or read the expiry; expires() resolves null when none is set.
indexedDB, caches, getDirectory() IDBFactory, CacheStorage, Promise<FileSystemDirectoryHandle> The bucket-scoped storage endpoints.

open(), keys(), and delete() reject rather than throw, except for the synchronous SecurityError Chromium raises when the whole API is unavailable to the context.

Exception Method Condition
TypeError open(), keys(), delete(), estimate() No storage shelf is available for the origin (opaque origin, storage disabled); open() also rejects for an invalid name, an expires in the past, or a quota of zero or less.
InvalidCharacterError delete() Invalid bucket name, per the specification. Chromium rejects with TypeError here instead (see the observed note).
InvalidStateError persist(), persisted(), estimate(), setExpires(), expires() The bucket’s removed flag is set: it was deleted or expired after you obtained the handle.
QuotaExceededError open() Chromium-specific: the origin has created more buckets than the implementation allows (Too many buckets created.).
UnknownError open(), keys(), delete() Chromium-specific: the storage backend failed (Unknown error occured while creating a bucket., the typo is Chromium’s).
SecurityError any (thrown synchronously) Chromium denies the API in this context, for example an opaque origin: Access to Storage Buckets API is denied in this context.

Both examples resolve a storage endpoint first and run the same application code against it, so the fallback for Firefox and Safari is the origin’s default storage rather than a second code path.

Keeping drafts in a persisted bucket with the default IndexedDB as fallback

Section titled “Keeping drafts in a persisted bucket with the default IndexedDB as fallback”

Drafts are the data the user would miss most, so they go in a bucket that asks for persisted: true. When navigator.storageBuckets is missing the same database opens on window.indexedDB, and when the persistence request is refused the code says so instead of assuming the bucket is safe.

function openDatabase(factory, name, version) {
return new Promise((resolve, reject) => {
const request = factory.open(name, version);
request.onupgradeneeded = () => request.result.createObjectStore('drafts', { keyPath: 'id' });
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function openDraftsDatabase() {
if (!('storageBuckets' in navigator)) {
return { db: await openDatabase(indexedDB, 'drafts', 1), persisted: false };
}
const bucket = await navigator.storageBuckets.open('drafts', { persisted: true });
return {
db: await openDatabase(bucket.indexedDB, 'drafts', 1),
persisted: await bucket.persisted(), // false until persistent-storage is granted
};
}
const { db, persisted } = await openDraftsDatabase();
if (!persisted) {
document.querySelector('#storage-note').textContent =
'Drafts are stored best-effort and may be cleared under storage pressure.';
}

The persisted flag comes back false in a fresh Chrome profile because persistent-storage has not been granted; calling navigator.storage.persist() from a user gesture first changes that outcome.

A news feed cached for offline reading is worth keeping for a week and worthless after. The bucket carries an expires timestamp so the browser removes it without a cleanup job; the fallback stores the same responses in the default caches and prunes them by a stored date.

const WEEK = 7 * 24 * 60 * 60 * 1000;
async function feedCache() {
if ('storageBuckets' in navigator) {
const bucket = await navigator.storageBuckets.open('feed', { expires: Date.now() + WEEK });
return bucket.caches.open('articles');
}
const cache = await caches.open('articles');
const stamp = await cache.match('/__cached-at');
if (stamp && Date.now() - Number(await stamp.text()) > WEEK) {
await caches.delete('articles');
return caches.open('articles');
}
if (!stamp) await cache.put('/__cached-at', new Response(String(Date.now())));
return cache;
}
const cache = await feedCache();
await cache.add('/api/feed?page=1');

Opening an existing bucket does not refresh its expiry, so a long-lived feed bucket needs bucket.setExpires(Date.now() + WEEK) after each successful sync to keep sliding the deadline.

Specifications

SpecificationStatus
Storage BucketsWICG draft
Storage Buckets API: open() methodWICG draft
Storage Buckets API: the StorageBucket interfaceWICG draft
  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)Yes122lowsource12
Chrome (Android)Yes122lowsource3
Edge (Desktop)Yes122lowsource4
Firefox (Desktop)No—lowsource5
Safari (macOS)No—lowsource6
  1. StorageBucketManager (navigator.storageBuckets) shipped in Chrome 122, per MDN browser-compat-data.
  2. This entry has no MDN prose page yet; verified against caniuse's per-browser support table for this feature.
  3. Mirrors Chrome Desktop support per MDN browser-compat-data.
  4. Mirrors Chromium support per MDN browser-compat-data.
  5. Not implemented; tracked as an open Firefox bug per MDN browser-compat-data.
  6. Not implemented, per MDN browser-compat-data.

Source data: /compatibility/storage-buckets.json · Global usage: 69 % (StatCounter 2026-05)

Source: spec · Last verified 2026-09-04 · Confidence: low (computed from sources)