# How to Configure OpenRaft Storage: Implementing Log and State Machine Traits

> Configure OpenRaft storage by implementing RaftLogStorage and RaftStateMachine traits. Learn how to declare them with TypeConfig and pass instances to Raft::new for efficient log and state management.

- Repository: [Databend Labs/openraft](https://github.com/databendlabs/openraft)
- Tags: how-to-guide
- Published: 2026-02-28

---

**To configure OpenRaft storage, implement the `RaftLogStorage` and `RaftStateMachine` traits, declare them in a `TypeConfig` using the `declare_raft_types!` macro, and pass instances to `Raft::new`.**

OpenRaft is a Raft consensus implementation in Rust that separates the consensus engine from the persistence layer. To configure OpenRaft storage for your application, you must provide concrete implementations for log storage and state machine storage. This guide walks through the trait definitions, implementation steps, and testing procedures using the databendlabs/openraft repository.

## Understanding OpenRaft Storage Architecture

OpenRaft uses a two-component storage model that separates log persistence from state machine persistence. This separation allows you to optimize each component independently based on your durability and performance requirements.

### The Two-Storage Model

You must provide two distinct storage components when configuring OpenRaft:

- **Log storage** – Implements the `RaftLogStorage` trait. This handles append-only log entries, log truncation, and vote persistence.
- **State-machine storage** – Implements the `RaftStateMachine` trait. This handles log entry application, snapshot creation, and snapshot installation.

According to the OpenRaft source code, this separation exists because Raft only requires ordering guarantees for the log, while the state machine can be rebuilt from snapshots and may use a different durability model.

### Key Traits and Source Files

The core storage traits are defined in the `openraft` crate under the `storage/v2` module:

- `RaftLogStorage` – Defined in [`openraft/src/storage/v2/raft_log_storage.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/storage/v2/raft_log_storage.rs)
- `RaftStateMachine` – Defined in [`openraft/src/storage/v2/raft_state_machine.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/storage/v2/raft_state_machine.rs)

## Implementing RaftLogStorage

The `RaftLogStorage` trait defines how OpenRaft persists and retrieves log entries and hard state (voted_for and term).

### Required Methods

Your implementation must provide the following async methods as defined in [`raft_log_storage.rs`](https://github.com/databendlabs/openraft/blob/main/raft_log_storage.rs):

- `append` – Append log entries to the store
- `truncate_after` – Delete log entries after a specific index
- `purge` – Permanently remove log entries up to a specific index
- `save_vote` – Persist the hard state (voted_for and current_term)
- `get_log_state` – Retrieve the current log state (last_log_id, etc.)
- `get_log_reader` – Return a reader for log entries

### In-Memory Reference Implementation

For testing and development, OpenRaft provides an in-memory implementation in [`stores/memstore/src/lib.rs`](https://github.com/databendlabs/openraft/blob/main/stores/memstore/src/lib.rs). This serves as a reference for implementing the trait:

```rust
use openraft::storage::RaftLogStorage;
use openraft::LogId;
use openraft::Vote;

pub struct LogStore {
    // Implementation details...
}

impl RaftLogStorage<TypeConfig> for LogStore {
    async fn append(
        &mut self,
        entries: &[Entry<TypeConfig>],
    ) -> Result<(), StorageError<TypeConfig>> {
        // Append entries to internal storage
        unimplemented!()
    }

    async fn save_vote(
        &mut self,
        vote: &Vote<NodeId>,
    ) -> Result<(), StorageError<TypeConfig>> {
        // Persist vote
        unimplemented!()
    }
    
    // ... other required methods
}

```

## Implementing RaftStateMachine

The `RaftStateMachine` trait handles the application of committed log entries to your state machine and manages snapshotting.

### Snapshot and Apply Operations

As defined in [`openraft/src/storage/v2/raft_state_machine.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/storage/v2/raft_state_machine.rs), your implementation must provide:

- `apply` – Apply a batch of log entries to the state machine, returning the responses
- `applied_state` – Return the last applied log ID and membership state
- `begin_receiving_snapshot` – Prepare to receive a snapshot stream from the leader
- `install_snapshot` – Install a snapshot into the state machine, replacing current state
- `get_snapshot_builder` – Return a builder for creating snapshots

### RocksDB Example Reference

For production use, the RocksDB example in [`examples/rocksstore/src/state_machine.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/state_machine.rs) demonstrates a persistent implementation:

```rust
use openraft::storage::RaftStateMachine;
use openraft::Snapshot;

pub struct RocksStateMachine {
    db: Arc<rocksdb::DB>,
    // ... other fields
}

impl RaftStateMachine<TypeConfig> for RocksStateMachine {
    async fn apply(
        &mut self,
        entries: Vec<Entry<TypeConfig>>,
    ) -> Result<Vec<Response>, StorageError<TypeConfig>> {
        // Apply entries to RocksDB
        unimplemented!()
    }

    async fn install_snapshot(
        &mut self,
        meta: &SnapshotMeta<TypeConfig>,
        snapshot: Box<dyn SnapshotData>,
    ) -> Result<(), StorageError<TypeConfig>> {
        // Install snapshot into RocksDB
        unimplemented!()
    }
    
    // ... other required methods
}

```

## Configuring the TypeConfig

Before instantiating the Raft node, you must declare your concrete types using the type configuration system.

### Using declare_raft_types!

The `declare_raft_types!` macro binds your application-specific types to the Raft generic parameters. As shown in [`examples/rocksstore/src/lib.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/lib.rs):

```rust
use openraft::declare_raft_types;

declare_raft_types!(
    pub TypeConfig:
        D = Request,      // Your client request type
        R = Response,     // Your client response type
        NodeId = u64,     // Node identifier type
        Node = BasicNode, // Node address type
        Entry = Entry<TypeConfig>,
        SnapshotData = Cursor<Vec<u8>>,
);

```

### Wiring Storage into Raft::new

After implementing the traits and declaring the types, instantiate the Raft node by passing the storage implementations to `Raft::new` as documented in [`openraft/src/docs/getting_started/getting-started.md`](https://github.com/databendlabs/openraft/blob/main/openraft/src/docs/getting_started/getting-started.md):

```rust
use openraft::Raft;

// Create storage instances
let log_store = MyLogStore::new().await?;
let state_machine = Arc::new(MyStateMachine::new().await?);

// Create Raft node
let raft = Raft::new(
    node_id,
    config,
    network_impl,
    log_store,
    state_machine,
).await?;

```

## Testing Your Storage Implementation

OpenRaft provides a comprehensive test harness to verify that your storage implementation satisfies the Raft safety requirements.

### The StoreBuilder Trait

The `StoreBuilder` trait in [`openraft/src/testing/log/store_builder.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/testing/log/store_builder.rs) defines how to construct fresh storage instances for testing:

```rust
use openraft::testing::log::StoreBuilder;
use openraft::StorageError;

#[async_trait::async_trait]
impl StoreBuilder<TypeConfig, MyLogStore, MyStateMachine, ()> for MyBuilder {
    async fn build(&self) -> Result<((), MyLogStore, MyStateMachine), StorageError<TypeConfig>> {
        let log_store = MyLogStore::new().await?;
        let sm = MyStateMachine::new().await?;
        Ok(((), log_store, sm))
    }
}

```

### Running Suite::test_all

Invoke the comprehensive test suite from [`openraft/src/testing/log/suite.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/testing/log/suite.rs) to validate your implementation:

```rust
use openraft::testing::log::Suite;

#[tokio::test]
async fn test_my_storage() {
    let builder = MyBuilder {};
    Suite::test_all(builder).await.unwrap();
}

```

The RocksDB example demonstrates this pattern in [`examples/rocksstore/src/test.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/test.rs).

## Summary

- **OpenRaft requires two storage components**: Implement `RaftLogStorage` for log persistence and `RaftStateMachine` for state machine operations and snapshots.
- **Core trait definitions** are located in [`openraft/src/storage/v2/raft_log_storage.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/storage/v2/raft_log_storage.rs) and [`openraft/src/storage/v2/raft_state_machine.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/storage/v2/raft_state_machine.rs).
- **Type configuration** uses the `declare_raft_types!` macro to bind your concrete storage types to the Raft generic system.
- **Reference implementations** include the in-memory `memstore` ([`stores/memstore/src/lib.rs`](https://github.com/databendlabs/openraft/blob/main/stores/memstore/src/lib.rs)) for testing and the RocksDB example ([`examples/rocksstore/src/lib.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/lib.rs)) for production persistence.
- **Validation** requires implementing the `StoreBuilder` trait and running `Suite::test_all` to ensure safety compliance before deployment.

## Frequently Asked Questions

### What is the difference between RaftLogStorage and RaftStateMachine?

`RaftLogStorage` persists the Raft log entries, hard state (voted_for and current_term), and provides log truncation and purging operations. It ensures durability of the consensus log. `RaftStateMachine` applies committed log entries to your application state, manages snapshot creation, and handles snapshot installation from the leader. The separation allows the log to use fast append-only storage while the state machine uses a database optimized for random access.

### Can I use different storage backends for logs and state machine?

Yes. OpenRaft explicitly separates these concerns so you can use different backends. For example, you might store logs in a high-performance append-only file or dedicated log store while keeping the state machine in RocksDB or an in-memory data structure. The RocksDB example (`examples/rocksstore`) demonstrates using the same RocksDB instance for both, but you can implement the traits to use completely different backends.

### How do I verify my storage implementation is correct?

You must implement the `StoreBuilder` trait from [`openraft/src/testing/log/store_builder.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/testing/log/store_builder.rs) and run the comprehensive test suite using `Suite::test_all` from [`openraft/src/testing/log/suite.rs`](https://github.com/databendlabs/openraft/blob/main/openraft/src/testing/log/suite.rs). This suite validates log consistency, snapshot behavior, and recovery scenarios. The RocksDB example in [`examples/rocksstore/src/test.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/test.rs) demonstrates the standard pattern for integrating with this test harness.

### Where can I find a complete production-ready storage example?

The RocksDB example in `examples/rocksstore/` provides a full production-ready reference implementation. Key files include [`examples/rocksstore/src/lib.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/lib.rs) for the storage constructor and type configuration, [`examples/rocksstore/src/state_machine.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/state_machine.rs) for the state machine implementation, and [`examples/rocksstore/src/test.rs`](https://github.com/databendlabs/openraft/blob/main/examples/rocksstore/src/test.rs) for the test harness integration. For a simpler in-memory reference suitable for testing, see [`stores/memstore/src/lib.rs`](https://github.com/databendlabs/openraft/blob/main/stores/memstore/src/lib.rs).