Hyperdrive
Secure real-time distributed filesystem built on Hypercore-based storage.
Hyperdrive stores filesystem metadata in a Hyperbee and file contents in a blob store, typically backed by one Corestore. Use this page for the instance surface; use the linked how-to guides for end-to-end replication flows.
For when to choose Hyperdrive over Hyperblobs or raw Hypercore, see From append-only logs to files.
Install
npm i hyperdriveQuickstart
import Corestore from 'corestore'
import Hyperdrive from 'hyperdrive'
const store = new Corestore('./storage')
const drive = new Hyperdrive(store)
await drive.ready()
await drive.put('/hello.txt', Buffer.from('hello world'), {
metadata: { type: 'text/plain' }
})
const buffer = await drive.get('/hello.txt')
const entry = await drive.entry('/hello.txt')
console.log(buffer.toString())
console.log(entry?.value.metadata)
await drive.close()API Reference
Constructor and lifecycle
new Hyperdrive(store, [key])
Creates a new Hyperdrive instance. store must be an instance of Corestore.
| Parameter | Type | Default | Description |
|---|---|---|---|
corestore | Corestore | — | — |
key | Buffer | — | Public key of an existing drive to load. May be omitted, passing opts in its place. |
opts | DriveOptions | {} | Drive options. |
const Corestore = require('corestore')
const store = new Corestore('./storage')
const drive = new Hyperdrive(store)await drive.ready()
Waits until internal state is loaded.
await drive.close()
Fully close this drive, including its underlying Hypercore backed datastructures.
await drive.purge()
Purge both cores (db and blobs) from your storage, completely removing all the drive's data.
- Returns:
Promise<void>— Resolves once both cores are purged from storage. - Throws: if called on a non-main session — only the main session can be purged.
await drive.purge()Drive properties
drive.corestore
The Corestore instance used as storage.
- Returns:
Corestore
drive.db
The underlying Hyperbee backing the drive file structure.
- Returns:
Hyperbee
drive.core
The Hypercore used for drive.db.
- Returns:
Hypercore
drive.id
String containing the id (z-base-32 of the public key) identifying this drive.
- Returns:
string
drive.key
The public key of the Hypercore backing the drive.
- Returns:
Buffer
drive.discoveryKey
The hash of the public key of the Hypercore backing the drive.
- Returns:
Buffer
drive.contentKey
The public key of the Hyperblobs instance holding blobs associated with entries in the drive.
- Returns:
Buffer
drive.writable
Boolean indicating if we can write or delete data in this drive.
- Returns:
boolean
drive.readable
Boolean indicating if we can read from this drive. After closing the drive this will be false.
- Returns:
boolean
drive.version
Number that indicates how many modifications were made, useful as a version identifier.
- Returns:
number
drive.supportsMetadata
Boolean indicating if the drive handles or not metadata. Always true.
- Returns:
boolean
Files
await drive.put(path, buffer, [options])
Creates a file at path in the drive. options are the same as in createWriteStream.
| Parameter | Type | Default | Description |
|---|---|---|---|
path | string | — | Path to write the file at. |
buffer | Buffer | — | Blob contents to store. |
options | WriteOptions | {} | — |
- Returns:
Promise<void>— Resolves once the file has been written.
await drive.put('/blob.txt', Buffer.from('example'))await drive.get(path, [options])
Reads the blob stored at path and resolves with its contents as a Buffer. Resolves with null when no blob exists at path, and also returns null for symbolic links.
| Parameter | Type | Description |
|---|---|---|
path | string | Path of the file to read. |
options | GetOptions | — |
- Returns:
Promise<Buffer\|null>— The blob atpath, ornullif the path does not exist or is a symbolic link. - Throws:
BLOCK_NOT_AVAILABLEif a required block is not available.
await drive.entry(path, [options])
Resolves with the entry stored at path, or null if no entry exists.
| Parameter | Type | Description |
|---|---|---|
path | string | Path of the entry to read. |
options | EntryOptions | — |
- Returns:
Promise<object>— the entry atpathin the drive. - Throws: if a symlink chain is recursive or exceeds 16 hops when
followis enabled.
| Option | Default |
|---|---|
seq | Number |
key | String |
value | — |
await drive.exists(path)
Checks whether an entry exists at path.
| Parameter | Type | Description |
|---|---|---|
path | string | Path to check. |
- Returns:
Promise<boolean>—trueif the entry atpathdoes exists, otherwisefalse.
const exists = await drive.exists('/blob.txt')await drive.has(path)
Checks if path is saved to local store already.
| Parameter | Type | Description |
|---|---|---|
path | string | of the file or folder to check. |
- Returns:
Promise<boolean>—trueif the blob (or every blob under a folder) is stored locally.
const exists = await drive.has('/blob.txt')await drive.del(path)
Deletes the file at path from the drive.
| Parameter | Type | Description |
|---|---|---|
path | string | Path of the file to delete. |
- Returns:
Promise<void>— Resolves once the entry has been deleted.
await drive.del('/blob.txt')await drive.clear(path, [options])
Deletes the blob from storage to free up space, but the file structure reference is kept.
| Parameter | Type | Description |
|---|---|---|
path | string | Path of the file whose blob should be cleared. |
options | ClearOptions | — |
- Returns:
Promise<object>— A{ blocks }object whendiffis enabled, otherwisenull.
await drive.clearAll([options])
Deletes all the blobs from storage to free up space, similar to how drive.clear() works.
| Parameter | Type |
|---|---|
options | ClearOptions |
- Returns:
Promise<object>— A{ blocks }object whendiffis enabled, otherwisenull.
await drive.symlink(path, linkname)
Creates an entry in drive at path that points to the entry at linkname.
| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | — | Path of the symlink to create. |
dst | string | — | Path the symlink points to. |
options | SymlinkOptions | {} | Symlink options. |
- Returns:
Promise<void>— Resolves once the symlink entry has been created.
await drive.symlink('/images/logo.shortcut', '/images/logo.png')drive.createReadStream(path, [options])
Returns a readable stream of the blob stored in the drive at path.
| Parameter | Type | Description |
|---|---|---|
path | string | Path of the file to read. |
options | object | — |
- Returns:
Readable— a stream to read out the blob stored in the drive atpath.
| Option | Default | Description |
|---|---|---|
start | Number | start and end are inclusive |
end | Number | — |
length | Number | length overrides end, they're not meant to be used together |
wait | true | Wait for blocks to be downloaded |
timeout | 0 | Wait at max some milliseconds (0 means no timeout) |
drive.createWriteStream(path, [options])
Stream a blob into the drive at path.
| Parameter | Type | Default | Description |
|---|---|---|---|
path | string | — | Path of the file to write. |
options | WriteOptions | {} | Write options — the same as for drive.put(path, buffer, [options]). |
- Returns:
Writable— A writable stream; data written is stored as the file's blob.
Directories and listings
drive.list(folder, [options])
Returns a stream of all entries in the drive at paths prefixed with folder.
| Parameter | Type | Default | Description |
|---|---|---|---|
folder | string | — | Path prefix to list. Defaults to the whole drive. |
options | object | {} | — |
- Returns:
Readable— a stream of all entries in the drive at paths prefixed withfolder.
| Option | Default | Description |
|---|---|---|
recursive | — | Whether to descend into all subfolders or not |
ignore | — | Ignore files and folders by name |
wait | true | Wait for block to be downloaded. |
drive.readdir(folder, [options])
Returns a stream of the immediate subpaths of entries stored at paths prefixed by folder.
| Parameter | Type | Description |
|---|---|---|
folder | string | Path prefix to read. |
options | object | — |
- Returns:
Readable— a stream of all subpaths of entries in drive stored at paths prefixed byfolder.
| Option | Default | Description |
|---|---|---|
wait | true | Wait for block to be downloaded |
await drive.entries([range], [options])
Returns a read stream of the drive entries within the given Hyperbee range.
| Parameter | Type | Description |
|---|---|---|
range | object | Hyperbee range bounds (gt/gte/lt/lte). |
options | object | options are the same as Hyperbee().createReadStream([range], [options]). |
- Returns:
Readable— a read stream of entries in the drive.
for await (const entry of drive.entries()) console.log(entry.key)drive.compare(entryA, entryB)
Compares two entries by their sequence number.
| Parameter | Type | Description |
|---|---|---|
entryA | object | The first entry (as returned by drive.entry()). |
entryB | object | The second entry (as returned by drive.entry()). |
- Returns:
number—0if entries are the same,1ifentryAis newer, and-1ifentryBis newer.
const comparison = drive.compare(entryA, entryB)drive.watch([folder])
Returns an async iterator that watches folder (defaults to /) and yields [current, previous] snapshot pairs whenever the drive changes. The snapshots are auto-closed before the next value, so do not close them yourself.
| Parameter | Type | Description |
|---|---|---|
folder | string | to watch. Defaults to /. |
- Returns:
Watcher— an iterator that listens onfolderto yield changes, by default on/.
for await (const [current, previous] of watcher) {
console.log(current.version)
console.log(previous.version)
}Versions and batched mutations
drive.batch()
Useful for atomically mutate the drive, has the same interface as Hyperdrive.
- Returns:
Hyperdrive— A batch with the same interface as Hyperdrive; callbatch.flush()to commit.
const batch = drive.batch()
await batch.put('/a.txt', Buffer.from('a'))
await batch.flush()await batch.flush()
Commit a batch of mutations to the underlying drive.
- Returns:
Promise<void>— Resolves once the batch is committed and closed.
await batch.flush()drive.checkout(version)
Get a read-only snapshot of a previous version.
| Parameter | Type | Description |
|---|---|---|
version | number | Drive version to snapshot. |
- Returns:
Hyperdrive— A read-only Hyperdrive at the requested version.
const snapshot = drive.checkout(4)drive.diff(version, folder, [options])
Efficiently create a stream of the changes to folder between version and drive.version.
| Parameter | Type | Description |
|---|---|---|
version | number | Drive version to diff against the current drive.version. |
folder | string | Path prefix to scope the diff to. Omit for the whole drive. |
options | object | Diff options, forwarded to the underlying Hyperbee diff stream. |
- Returns:
Readable— A stream of{ left, right }diff entries.
| Option | Default | Description |
|---|---|---|
left | Object | Entry in folder at drive.version for some path |
right | Object | Entry in folder at drive.checkout(version) for some path |
await drive.truncate(version, [options] })
Truncates the Hyperdrive to a previous version (both the file-structure reference and the blobs).
| Parameter | Type | Default | Description |
|---|---|---|---|
version | number | — | Drive version to truncate to. |
options | TruncateOptions | {} | Truncate options. |
- Returns:
Promise<void>— Resolves once the drive and its blobs are truncated. - Throws:
BAD_ARGUMENTif the truncation length is invalid.
await drive.truncate(drive.version - 1)Replication, downloads, and blob access
drive.mirror(out, [options])
Efficiently mirror this drive into another. Returns a MirrorDrive instance constructed with options.
| Parameter | Type | Description |
|---|---|---|
out | Hyperdrive|Localdrive | Destination drive to mirror into. |
options | object | Mirror options, forwarded to MirrorDrive. |
- Returns:
MirrorDrive— AMirrorDriveinstance; await it ormirror.done()to finish.
const mirror = drive.mirror(out)
await mirror.done()drive.download(folder, [options])
Downloads the blobs corresponding to all entries in the drive at paths prefixed with folder. Returns a Download object that resolves once all data has been downloaded:
| Parameter | Type | Default | Description |
|---|---|---|---|
folder | string | '/' | Path prefix to download. Defaults to the whole drive. |
options | object | — | options are the same as those for drive.list(folder, [options]). |
- Returns:
Download— A Download object; awaitdownload.done()to know when complete.
const download = await drive.download(key)
await download.done()download.destroy()await drive.downloadDiff(version, folder, [options])
Downloads all the blobs in folder corresponding to entries in drive.checkout(version) that are not in drive.version. Returns a Download object that resolves once all data has been downloaded:
| Parameter | Type | Description |
|---|---|---|
version | number | Drive version to diff against the current drive.version. |
folder | string | Path prefix to scope the download to. Omit for the whole drive. |
options | object | Diff options, forwarded to drive.diff(). |
- Returns:
Download— A Download object; awaitdownload.done()to know when complete.
const download = await drive.downloadDiff(version, folder)
await download.done()download.destroy()await drive.downloadRange(dbRanges, blobRanges)
Downloads the entries and blobs stored in the ranges dbRanges and blobRanges. Returns a Download object that resolves once all data has been downloaded:
| Parameter | Type | Description |
|---|---|---|
dbRanges | Array<object> | Block ranges to download from the db (metadata) core. |
blobRanges | Array<object> | Block ranges to download from the blobs core. |
- Returns:
Download— A Download object; awaitdownload.done()to know when complete.
const download = await drive.downloadRange(dbRanges, blobRanges)
await download.done()download.destroy()drive.findingPeers()
Indicate to Hyperdrive that you're finding peers in the background, requests will be on hold until this is done.
- Returns:
Function— Adonecallback to call once peer discovery has finished.
const done = drive.findingPeers()
swarm.flush().then(done, done)drive.replicate(isInitiatorOrStream)
Creates a replication stream for the drive. Pass true/false to create a new stream as initiator/responder, or pass an existing stream or socket to replicate over it. See corestore.replicate for how replication works.
| Parameter | Type | Description |
|---|---|---|
isInitiator | boolean|Stream | true/false to initiate replication, or an existing stream/socket to replicate over. |
opts | object | Replication options, forwarded to corestore.replicate(). |
- Returns:
Stream— A replication stream.
const swarm = new Hyperswarm()
const done = drive.findingPeers()
swarm.on('connection', (socket) => drive.replicate(socket))
swarm.join(drive.discoveryKey)
swarm.flush().then(done, done)await drive.update([options])
Waits for initial proof of the new drive version until all findingPeers are done.
| Parameter | Type |
|---|---|
options | UpdateOptions |
- Returns:
Promise<boolean>—trueif the drive advanced to a new version, otherwisefalse.
await drive.getBlobs()
Returns the Hyperblobs instance storing the blobs indexed by drive entries.
- Returns:
Promise<Hyperblobs>— the Hyperblobs instance storing the blobs indexed by drive entries.
await drive.put('/file.txt', Buffer.from('hi'))
const buffer1 = await drive.get('/file.txt')
const blobs = await drive.getBlobs()
const entry = await drive.entry('/file.txt')
const buffer2 = await blobs.get(entry.value.blob)
// => buffer1 and buffer2 are equalsawait drive.getBlobsLength(checkout)
Returns the length of the Hyperblobs instance at the time of the specified Hyperdrive version (defaults to the current version).
| Parameter | Type | Description |
|---|---|---|
checkout | number | Drive version to measure. Defaults to the current version. |
- Returns:
Promise<number>— the length of the Hyperblobs instance at the time of the specified Hyperdrive version (defaults to the current version).
const blobsLength = await drive.getBlobsLength()Types
DriveOptions
Options for creating a Hyperdrive.
| Property | Type | Default | Description |
|---|---|---|---|
encryptionKey | Buffer | — | Encryption key used to encrypt and decrypt the underlying cores. |
onwait | Function | — | Hook called when a block has to be downloaded before it can be read. |
active | boolean | true | Whether the drive's cores actively maintain peer connections. |
TruncateOptions
Options for drive.truncate().
| Property | Type | Default | Description |
|---|---|---|---|
blobs | number | — | Corresponding blobs length, if known. Recommended to let the method figure it out. |
UpdateOptions
Options for drive.update().
| Property | Type | Default | Description |
|---|---|---|---|
wait | boolean | false | Whether to wait for peers before resolving. Use this or drive.findingPeers() to make await drive.update() blocking. |
GetOptions
Options for drive.get().
| Property | Type | Default | Description |
|---|---|---|---|
wait | boolean | true | Wait for the block to be downloaded. |
timeout | number | 0 | Max milliseconds to wait (0 means no timeout). |
WriteOptions
Options for writing a file (drive.put() and drive.createWriteStream()).
| Property | Type | Default | Description |
|---|---|---|---|
executable | boolean | false | Whether the blob at the path is an executable. |
metadata | * | null | Extended file information, i.e. an arbitrary JSON value. |
dedup | boolean | false | Reuse the existing blob if the content is unchanged (createWriteStream only). |
ClearOptions
Options for clearing blobs (drive.clear() and drive.clearAll()).
| Property | Type | Default | Description |
|---|---|---|---|
diff | boolean | false | When enabled, returns a { blocks } object reporting the blocks cleared; otherwise the result is null. |
SymlinkOptions
Options for drive.symlink().
| Property | Type | Default | Description |
|---|---|---|---|
metadata | * | null | Extended file information, i.e. an arbitrary JSON value. |
EntryOptions
Options for drive.entry().
| Property | Type | Default | Description |
|---|---|---|---|
follow | boolean | false | Follow symlinks, up to 16 deep or it throws an error. |
wait | boolean | true | Wait for the block to be downloaded. |
timeout | number | 0 | Max milliseconds to wait (0 means no timeout). |
Errors
Coded errors this module can throw — catch them via err.code.
| Error | Thrown when |
|---|---|
BAD_ARGUMENT | if the truncation length is invalid. |
BLOCK_NOT_AVAILABLE | if a required block is not available. |
See also
- Create a full peer-to-peer filesystem with Hyperdrive—end-to-end filesystem replication walkthrough.
- Work with many Hypercores using Corestore—recommended pattern when one app manages multiple drives or related cores.
- Localdrive—map a Hyperdrive-like API onto the local filesystem.
- Mirrordrive—sync between Hyperdrive and other drive-like destinations.
- Corestore—shared storage and replication manager for drive metadata and content.
- Hyperbee—Hyperdrive uses a Hyperbee internally for metadata indexing.
- Drives—CLI tool for creating, mirroring, and seeding Hyperdrives.