# Autobase



<Status level="stable" />

Autobase is a higher-level composition over underlying [Hypercores](/p2p/reference/building-blocks/hypercore). Writers append causal nodes to local cores, Autobase linearizes that graph into an eventually consistent order, and your `apply` handler materializes a deterministic view, often into a [Hyperbee](/p2p/reference/building-blocks/hyperbee).

## The apply handler [#the-apply-handler]

Treat `apply` like a **pure reducer**: given an ordered batch of nodes and a view handle, derive the next view state deterministically. Mutate only the `view` passed into `apply`. Do not:

* read or write external globals,
* open network connections, or
* assume ordering that Autobase has not yet committed.
  **Side effects belong outside the linearization path.**

Autobase can reorder previously seen nodes when new causal information arrives. If `apply` is non-deterministic, different peers will diverge. Writer management (`host.addWriter`, indexer flags) and migration between `apply` versions are advanced topics—keep them inside `apply` only when they operate on the provided `view` and `host` handles.

## Install [#install]

```sh
npm i autobase
```

## Quickstart [#quickstart]

This minimal flow opens a view, appends one record, updates the linearizer, and reads the materialized value back from `base.view`.

```js
import Corestore from 'corestore'
import Autobase from 'autobase'

const store = new Corestore('./autobase-demo')
const base = new Autobase(store, null, {
  valueEncoding: 'json',
  open: (viewStore) => viewStore.get({ name: 'messages', valueEncoding: 'json' }),
  apply: async (nodes, view) => {
    for (const { value } of nodes) await view.append(value)
  }
})

await base.ready()
await base.append({ type: 'message', text: 'hello from Autobase' })
await base.update()

console.log(await base.view.get(0))
// { type: 'message', text: 'hello from Autobase' }
```

Autobase can reorder previously seen nodes as new causal information arrives. Keep `open` and `apply` deterministic, derive state from the provided `store`, and mutate only the provided `view` inside `apply`.

## API Reference [#api-reference]

### Constructor and lifecycle [#constructor-and-lifecycle]

#### `new Autobase(store, bootstrap, opts)` [#new-autobasestore-bootstrap-opts]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L77)

Instantiate an Autobase.

| Parameter   | Type                                                                | Default | Description                                                                                                                                                        |
| ----------- | ------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `store`     | [`Corestore`](/p2p/reference/helpers/corestore)                     | —       | The Corestore that holds the system, writer, and view cores.                                                                                                       |
| `bootstrap` | [`Buffer\|string`](https://nodejs.org/api/buffer.html#class-buffer) | —       | Key of an existing Autobase to load; omit or pass `null` to create a new one.                                                                                      |
| `opts`      | `object`                                                            | `{}`    | Configuration: `open`, `apply`, `close`, `valueEncoding`, `ackInterval`, `fastForward`, `encrypt`/`encryptionKey`, `optimistic`, and more (see the options table). |

| Option          | Default | Description                                                                                                   |
| --------------- | ------- | ------------------------------------------------------------------------------------------------------------- |
| `open`          | —       | create the view                                                                                               |
| `apply`         | —       | handle nodes to update view                                                                                   |
| `optimistic`    | `false` | Autobase supports optimistic appends                                                                          |
| `close`         | —       | close the view                                                                                                |
| `valueEncoding` | —       | encoding                                                                                                      |
| `ackInterval`   | `10000` | enable auto acking with the interval                                                                          |
| `encryptionKey` | —       | Key to encrypt the base                                                                                       |
| `encrypt`       | `false` | Encrypt the base if unencrypted & no encryptionKey is set                                                     |
| `encrypted`     | `false` | Expect the base to be encrypted, will throw an error otherwise, defaults to true if encryptionKey is set      |
| `fastForward`   | `true`  | Enable fast forwarding. If passing \{ key: base.core.key }, they autobase will fastforward to that key first. |
| `wakeup`        | —       | Set a custom wakeup protocol for hinting which writers are active, see `protomux-wakeup` for protocol details |
| `bigBatches`    | `false` | Enable big batches. See `base.setBigBatches()` for details.                                                   |

```js
const base = new Autobase(store, bootstrap, {
  optimistic: true,
  async apply(nodes, view, host) {
    for (const node of nodes) {
      const { value } = node
      // Verify block
      if (value.password !== 'secrets') continue

      // Acknowledge only even numbers
      if (value.num % 2 === 0) await host.ackWriter(node.from.key)

      await view.append(value.num)
    }
  }
})

// Passing the password 'secrets' represents being verifiable
await base.append({ num: 3, password: 'secrets' }, { optimistic: true }) // will not be applied because `ackWriter` isnt called
await base.append({ num: 2, password: 'secrets' }, { optimistic: true }) // will be applied
await base.append({ num: 4, password: 'incorrect' }, { optimistic: true }) // will not be applied because the block isn't verifiable
```

When `optimistic` is enabled, validate optimistic blocks inside `apply` before calling `host.ackWriter(key)`. Otherwise any peer that can write to the underlying network path could attempt to inject values.

#### `await base.ready()` [#await-baseready]

Resolves once the base and its view are open and ready to use.

### State and derived view [#state-and-derived-view]

#### `base.view` [#baseview]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L187)

The view of the autobase derived from writer inputs. The view is created in the `open` handler and can have any shape. The most common `view` is a [hyperbee](https://github.com/holepunchto/hyperbee).

* Returns: `*`

#### `base.key` [#basekey]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L90)

The primary key of the autobase.

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)

#### `base.discoveryKey` [#basediscoverykey]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L91)

The discovery key associated with the autobase.

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)

#### `base.isIndexer` [#baseisindexer]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L110)

Whether the instance is an indexer.

* Returns: `boolean`

#### `base.writable` [#basewritable]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L242)

Whether the instance is a writer for the autobase.

* Returns: `boolean`

#### `base.length` [#baselength]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L258)

The length of the system core. This is neither the length of the local writer nor the length of the view. The system core tracks the autobase as a whole.

* Returns: `number`

#### `base.signedLength` [#basesignedlength]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L250)

The index of the system core that has been signed by a quorum of indexers. The system up until this point will not change.

* Returns: `number`

#### `base.paused` [#basepaused]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L166)

Whether the base is currently paused.

* Returns: `boolean` — `true` if the autobase is currently paused, otherwise returns `false`.

### Writes and linearization [#writes-and-linearization]

#### `await base.append(value, opts)` [#await-baseappendvalue-opts]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1010)

Append a new entry to the autobase.

| Parameter | Type                                                                                                    | Description                               |
| --------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `value`   | [`*\|Array<*>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | The value, or array of values, to append. |
| `opts`    | [`AppendOptions`](#appendoptions)                                                                       | Append options.                           |

* Returns: [`Promise<number>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves to the new core length once the value (or batch) has been appended.
* Throws:
  * if the autobase is closing.
  * if the local writer is not active/writable.

#### `await base.update()` [#await-baseupdate]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L894)

Fetch all available data and update the linearizer.

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves once the linearizer has advanced.

```js
await base.update()
```

#### `await base.ack(bg = false)` [#await-baseackbg--false]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L934)

Manually acknowledge the current state by appending a `null` node that references known head nodes. `null` nodes are ignored by the `apply` handler and only serve as a way to acknowledge the current linearized state. Only indexers can ack.

| Parameter | Type      | Default | Description                                                                                                                             |
| --------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `bg`      | `boolean` | `false` | If `bg` is set to `true`, the ack will not be appended immediately but will set the automatic ack timer to trigger as soon as possible. |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves once the ack has been handled.

```js
await base.ack()
```

Only indexers can acknowledge. An ack appends a `null` node that references the known heads so peers can converge faster without changing the view.

#### `base.heads()` [#baseheads]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L297)

Gets the current writer heads. A writer head is a node which has no causal dependents, aka it is the latest write. If there is more than one head, there is a causal fork which is pretty common.

* Returns: [`Array<object>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) — The head nodes (empty until the base is ready).

```js
const heads = base.heads()
```

#### `await base.pause()` [#await-basepause]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1983)

Pauses the autobase, preventing the next apply from running until `resume()` is called.

* Returns: `void`

```js
base.pause()
```

#### `await base.resume()` [#await-baseresume]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1987)

Resumes a paused autobase and will check for an update.

* Returns: `void`

```js
base.resume()
```

#### `base.setBigBatches(enable = true)` [#basesetbigbatchesenable--true]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L326)

Set the autobase to enable or disable big batches. Big batches allow autobase to run the `apply` function on more blocks at once at the expense of being slower and less responsive.

| Parameter | Type      | Default | Description                    |
| --------- | --------- | ------- | ------------------------------ |
| `enable`  | `boolean` | `true`  | Whether to enable big batches. |

* Returns: `void`

```js
base.setBigBatches(true)
```

Big batches let Autobase call `apply` with more nodes at once, trading responsiveness for larger deterministic batches.

### Replication and metadata [#replication-and-metadata]

#### `await base.hash()` [#await-basehash]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L266)

Merkle-tree hash of the system core at its current length.

* Returns: [`Promise<Buffer>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — the hash of the system core's merkle tree roots.

```js
const hash = await base.hash()
```

#### `base.replicate(isInitiator || stream, opts)` [#basereplicateisinitiator--stream-opts]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L291)

Creates a replication stream for replicating the autobase. Arguments are the same as [corestores's `.replicate()`](https://github.com/holepunchto/corestore?tab=readme-ov-file#const-stream--storereplicateoptsorstream).

| Parameter     | Type                                                    | Description                                                                          |
| ------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `isInitiator` | [`boolean\|Stream`](https://nodejs.org/api/stream.html) | `true`/`false` to open a new stream, or an existing replication stream to attach to. |
| `opts`        | `object`                                                | Replication options forwarded to the underlying Corestore.                           |

* Returns: [`Stream`](https://nodejs.org/api/stream.html) — The replication stream.

```js
const swarm = new Hyperswarm()

// Join a topic
swarm.join(base.discoveryKey)

swarm.on('connection', (connection) => base.replicate(connection))
```

#### `await base.setUserData(key, value)` [#await-basesetuserdatakey-value]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1129)

Sets the [User Data](https://github.com/holepunchto/hypercore#user-data) value for the provided `key`. `key` is a string. `value` can be either a string or a buffer.

| Parameter | Type                                                                |
| --------- | ------------------------------------------------------------------- |
| `key`     | `string`                                                            |
| `value`   | [`Buffer\|string`](https://nodejs.org/api/buffer.html#class-buffer) |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves once written.

```js
await base.setUserData('nickname', 'alice')
```

#### `await base.getUserData(key)` [#await-basegetuserdatakey]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1136)

Read a local-only value previously stored with `setUserData()`.

| Parameter | Type     | Description  |
| --------- | -------- | ------------ |
| `key`     | `string` | is a string. |

* Returns: [`Promise<Buffer\|null>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — the [User Data](https://github.com/holepunchto/hypercore#user-data) value for the provided `key`.

```js
const nickname = await base.getUserData('nickname')
```

### Static helpers [#static-helpers]

#### `Autobase.getLocalCore(store, handlers, encryptionKey)` [#autobasegetlocalcorestore-handlers-encryptionkey]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1093)

Generate a local core to be used for an Autobase.

| Parameter       | Type                                                        | Description                                        |
| --------------- | ----------------------------------------------------------- | -------------------------------------------------- |
| `store`         | [`Corestore`](/p2p/reference/helpers/corestore)             | The Corestore to open the core from.               |
| `handlers`      | `object`                                                    | are any options passed to `store` to get the core. |
| `encryptionKey` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | Encryption key, when the core is encrypted.        |

* Returns: [`Hypercore`](/p2p/reference/building-blocks/hypercore) — The local writer core.

```js
const core = Autobase.getLocalCore(store)
```

#### `await Autobase.getUserData(core)` [#await-autobasegetuserdatacore]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1106)

Get user data associated with an autobase `core`. `referrer` is the `.key` of the autobase the `core` is from. `view` is the `name` of the view.

| Parameter | Type                                                    | Description                            |
| --------- | ------------------------------------------------------- | -------------------------------------- |
| `core`    | [`Hypercore`](/p2p/reference/building-blocks/hypercore) | The bootstrap/local core to read from. |

* Returns: [`Promise<{referrer: Buffer, view: string\|null}>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — The referrer and view name.

```js
const { referrer, view } = await Autobase.getUserData(core)
```

#### `await Autobase.isAutobase(core, opts)` [#await-autobaseisautobasecore-opts]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1115)

Detect whether a core's first block is an Autobase oplog message.

| Parameter | Type                                                    | Default | Description                                                                                                                                           |
| --------- | ------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `core`    | [`Hypercore`](/p2p/reference/building-blocks/hypercore) | —       | The core to inspect.                                                                                                                                  |
| `opts`    | `object`                                                | `{}`    | are the same options as [core.get(index, opts)](https://github.com/holepunchto/hypercore?tab=readme-ov-file#const-block--await-coregetindex-options). |

* Returns: [`Promise<boolean>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — whether the core is an autobase core.

```js
const isBase = await Autobase.isAutobase(core)
```

### View store helper [#view-store-helper]

#### `store.get(name || { name, valueEncoding })` [#storegetname---name-valueencoding-]

Load a `Hypercore` by name (passed as `name`). `name` should be passed as a string.

* Throws: if no `name` is provided.

This `store` instance is the `AutoStore` passed into `open`, and it is the intended place to create the cores that make up your deterministic view.

### Apply host calls [#apply-host-calls]

#### `await host.addWriter(key, { indexer = true })` [#await-hostaddwriterkey--indexer--true-]

Add a writer with the given `key` to the autobase allowing their local core to append. If `indexer` is `true`, it will be added as an indexer.

| Parameter   | Default  |
| ----------- | -------- |
| `{ indexer` | `true }` |

* Throws: if called on the read-only public view.

#### `await host.removeWriter(key)` [#await-hostremovewriterkey]

Remove a writer from the autobase. This will throw if the writer cannot be removed.

* Throws: if called on the read-only public view, or if it would remove the last indexer.

This throws when the writer cannot be removed, such as when it would leave the system without a removable indexer set.

#### `await host.ackWriter(key)` [#await-hostackwriterkey]

Acknowledge a writer even if they haven't been added before. This is most useful for applying `optimistic` blocks from writers that are not currently a writer.

* Throws: if called on the read-only public view.

#### `host.interrupt(reason)` [#hostinterruptreason]

Interrupt the applying of writer blocks optionally giving a `reason`. This will emit an `interrupt` event passing the `reason` to the callback and halt all further applying. The base is not closed, but `base.interrupted` is set to the `reason` and later `base.append()` calls reject.

* Throws: if called on the read-only public view.

Interrupting halts applying and emits the `interrupt` event so the application can upgrade its `apply` logic or recover intentionally.

#### `host.removeable(key)` [#hostremoveablekey]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/lib/apply-calls.js#L91)

Whether the writer with `key` can be removed without leaving the system
without a removable indexer set.

| Parameter | Type                                                        | Description       |
| --------- | ----------------------------------------------------------- | ----------------- |
| `key`     | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | The writer's key. |

* Returns: `boolean` — whether the writer for the given `key` can be removed.

```js
if (host.removeable(writerKey)) await host.removeWriter(writerKey)
```

The last indexer cannot be removed.

### Events [#events]

#### `base.on('update', () => { ... })` [#baseonupdate-----]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L2060)

Triggered when the autobase view updates after `apply` has finished running.

#### `base.on('interrupt', (reason) => { ... })` [#baseoninterrupt-reason----]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L838)

Triggered when `host.interrupt(reason)` is called in the `apply` handler. See [`host.interrupt(reason)`](#hostinterruptreason) for when interrupts are used.

#### `base.on('fast-forward', (to, from) => { ... })` [#baseonfast-forward-to-from----]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1502)

Triggered when the autobase fast forwards to a state already with a quorum. `to` and `from` are the `.signedLength` after and before the fast forward respectively.

#### `base.on('is-indexer', () => { ... })` [#baseonis-indexer-----]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1712)

Triggered when the autobase instance is an indexer.

#### `base.on('is-non-indexer', () => { ... })` [#baseonis-non-indexer-----]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L1723)

Triggered when the autobase instance is not an indexer.

#### `base.on('writable', () => { ... })` [#baseonwritable-----]

Triggered when the autobase instance is now a writer.

#### `base.on('unwritable', () => { ... })` [#baseonunwritable-----]

Triggered when the autobase instance is no longer a writer.

#### `base.on('warning', (warning) => { ... })` [#baseonwarning-warning----]

Triggered when a warning is triggered.

#### `base.on('error', (err) => { ... })` [#baseonerror-err----]

[src](https://github.com/holepunchto/autobase/blob/v7.28.2/index.js#L852)

Triggered when an error is triggered while updating the autobase.

## Types [#types]

### AppendOptions [#appendoptions]

Options for `base.append()`.

| Property     | Type      | Default | Description                                                                                                      |
| ------------ | --------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| `optimistic` | `boolean` | `false` | Allow appending on an optimistic Autobase while not a writer; the block is only applied if validated in `apply`. |

## See also [#see-also]

* [Build a multiwriter app with Autobase](/p2p/how-to/store-and-replicate/build-a-multiwriter-app-with-autobase)—two-peer walkthrough covering `open`, `apply`, and granting write access.
* [Work with many Hypercores using Corestore](/p2p/how-to/store-and-replicate/work-with-many-hypercores-using-corestore)—manage the groups of cores that Autobase coordinates.
* [Corestore](/p2p/reference/helpers/corestore)—storage and replication manager typically used for Autobase system, writer, and view cores.
* [Hypercore](/p2p/reference/building-blocks/hypercore)—append-only log primitive that Autobase writers build on.
* [Hyperbee](/p2p/reference/building-blocks/hyperbee)—common materialized-view target for deterministic indexed state.
* [Autobee](/p2p/reference/building-blocks/autobee)—the same linearization with the view fixed to a Hyperbee and the B-tree write path built in.
