Library / SDK
bitcoindevkit/bdk avatar
bitcoindevkit/bdk

BDK, and the split between chain backends and the wallet above them

A modern, lightweight, descriptor-based wallet library written in Rust!

1,077 stars519 forksRustNOASSERTION

At a glance

What is it?
The Bitcoin Dev Kit is a Rust workspace of six crates that handle chain data, with esplora, electrum and bitcoind backends all producing output in a shape the rest of the stack can consume. The high-level Wallet type lives in a separate repository, and one of the six crates is marked as unsuitable for production.
Who is it for?
BDK fits a Rust team building a Bitcoin wallet or any application that needs descriptor-aware key handling and chain data from a chosen backend, and it gives you a choice of esplora, electrum or bitcoind without changing the layer above.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Six crates in /crates, and the wallet that is not among them

The Bitcoin Dev Kit presents itself as a suite of libraries for building modern, lightweight, descriptor-based wallets written in Rust, built on top of the rust-bitcoin and rust-miniscript crates. The workspace contains several crates under a /crates directory, and the split is the interesting part of the design.

Six of them are named in the architecture table. `chain` is described as tools for storing and indexing chain data. `core` is a collection of core structures used by bdk_chain, by bdk_wallet and by the chain data source crates. `esplora`, `electrum` and `bitcoind_rpc` are the backends. And `file_store` is a persistence backend for chain data in a single file.

The seventh crate in the workspace manifest, `testenv`, is not in that table, which suggests it is a testing support crate rather than part of the public surface. The Cargo.toml workspace members list also shows `crates/testenv` alongside the six.

The wallet itself is absent, and that is deliberate rather than an omission. The README states that the bdk_wallet repository and crate contain a higher level Wallet type that depends on the lower-level mechanism crates. So the layering is: rust-bitcoin and rust-miniscript at the bottom, then core structures, then chain data handling, then three interchangeable backends, and the wallet in another repository on top. If you are evaluating this project, that split is the first thing to internalise, because it decides how many dependencies you take and how you track their versions.

Three backends, one shape of chain data

The mechanism that makes the backends interchangeable is stated in each of their descriptions. The esplora crate extends the esplora-client crate with methods to fetch chain data from an esplora HTTP server in the form that bdk_chain and Wallet can consume. The electrum crate extends electrum-client in the same way, for an electrum server. The bitcoind_rpc crate extends bitcoincore-rpc to emit blockchain data from the bitcoind RPC interface in the same consumable form.

That phrase, in the form that the chain layer and the wallet can consume, is the contract. Each backend is an adapter over an existing client crate, and its job is to normalise the output. esplora returns JSON over HTTP, electrum is a line protocol over a socket, and bitcoind is a JSON-RPC interface to a full node. Three quite different transports and payload shapes are turned into one representation before the wallet sees them.

The `core` crate is what makes that possible. It holds the core structures shared by bdk_chain, bdk_wallet and the data source crates, so the normalised representation has a single definition rather than one per backend. The result is a stack where a wallet written against bdk_chain does not know or care which of the three backends is feeding it, and where switching from a public esplora server to your own bitcoind is a change of data source rather than a change of application code.

The cost is that chain data is treated as something indexed and stored, not something streamed. bdk_chain is described as storing and indexing chain data, which is the right model for a wallet that needs confirmations and transaction history, and the wrong model for a workload that only wants a tip height or a balance.

file_store is marked as not for production

One crate carries an explicit warning in the architecture table, and it is worth reading twice. The file_store crate is a persistence backend for storing chain data in a single file, and the table says it is intended for testing and development purposes, not for production.

The qualification is narrow and deliberate. The crate fills a real gap: when you are writing tests or bringing up a new feature, you need somewhere to put chain data that is fast, local and disposable, and a single file is the simplest such place. The warning is there so nobody reaches for it as the storage layer of a wallet holding money, where the properties that matter are durability, crash safety, concurrent access and the ability to recover from a partially written state. None of those are claimed for a single-file backend, and the project is being straightforward about it rather than leaving you to discover the limits.

It is also the clearest example of the project's editorial style. A crate description in a table says what the crate is for and what it is not for, and a reader can decide accordingly. Contrast that with the backends, whose descriptions tell you what they extend and what shape they produce, and with the wallet, whose description tells you where it lives. Each line answers a different question because each crate answers a different question.

just recipes, nightly fmt, and a check that refuses unsigned commits

Development runs through a justfile, and the repository ships a set of recipes with short aliases: b for build, c for check, f for fmt, t for test, p for pre-push and d for doc. Running just with no arguments lists the available recipes, which is the documented first step.

The check recipe is the strictest part. It formats the workspace with nightly Rust, checks it with all features, runs clippy over all features and all targets with warnings denied, and then inspects the most recent commit:

bash
cargo +nightly fmt --all -- --check
cargo check --workspace --all-features
cargo clippy --all-features --all-targets -- -D warnings

The commit inspection is unusual enough to be worth knowing about. The recipe compares the signature status of the last commit and prints a warning when it is not signed, because BDK requires that commits be signed. So the lint gate and the release gate are treated as one thing here, which is a sensible position for a library that ends up in other people's wallets, and it means a contributor without a signing key configured will see a warning on every check.

Tests run per crate with all features enabled, one recipe each:

bash
cargo test -p bdk_chain --all-features
cargo test -p bdk_esplora --all-features

The pre-push recipe is simply fmt, check and test in that order, and the doc recipe builds the workspace documentation with rustdoc warnings denied, using the RUSTDOCFLAGS environment variable to turn warnings into errors.

An MSRV of 1.85.0 and a script that pins dependencies for it

The project states a minimum supported Rust version and then does something slightly unusual about it. The listed crates all maintain an MSRV of 1.85.0, and to build them at that version you need to pin dependencies by running the ci/pin-msrv.sh script.

The reasoning is familiar to anyone who maintains a library with a wide user base. A library that supports an old toolchain cannot simply let its dependency tree float forward, because a new version of a transitive dependency can raise the minimum Rust version without the library changing anything itself. Pinning the dependency graph for the MSRV build is how the claim is kept honest, and the script in the ci directory is the mechanism. There is also a rust-version file at the repository root, alongside the workspace Cargo.toml.

The badge row reflects the same posture from the other side, showing a required rustc version of 1.85.0 or later, and the toolchain policy is separated from the licence question in the README, which is a hint about how the maintainers prioritise things.

For an adopter, the practical consequence is small but real. If your build environment is on an older Rust, the crates in this repository build, but only with the pinned dependency set, and your Cargo.lock has to reflect it. The alternative, tracking the newest transitive dependencies, would quietly raise the floor for every user of the library.

MIT or Apache-2.0 at your option, and a security policy to read first

The licensing is the conventional dual arrangement for a Rust library: Apache License 2.0 or the MIT licence, at your option, with LICENSE-APACHE and LICENSE-MIT both in the repository root. The badge describes it as MIT or Apache-2.0 licensed.

The contribution terms are worth quoting because they are the part people miss. Unless a contribution states otherwise, it is dual licensed under the same terms, without any additional conditions. For a library that other teams will vendor into wallets, that clarity saves an argument later, and it is why the two licence files sit next to a SECURITY.md that tells readers where to report a security issue.

The rest of the repository structure supports the same picture of a project that expects to be reviewed. There is a CI workflow with its own status badge, coverage reporting through Coveralls, a CONTRIBUTING.md, a DEVELOPMENT_CYCLE.md describing how releases are paced, a nursery/ directory, and separate configuration for rustfmt and clippy at the root. The workspace also denies the stdout and stderr print lints at the workspace level, so a library crate cannot quietly print to the console of the application that embeds it.

For a wallet library, that combination of a security policy, a licence that is easy to reason about and a documented development cycle is the part that matters. The code is what people read later, but the process is what tells you whether the code will still be there.

Where the chain layer is the wrong shape for the job

There is a mismatch between the library and a project that wants the whole wallet in one place. The Wallet type is in a different repository, so adopting BDK means depending on two projects, tracking their release cycles separately, and reading documentation that spans both. That is a reasonable trade if you want a wallet with a specific storage model, and a poor one if you only need descriptor-aware keys, in which case the underlying rust-bitcoin and rust-miniscript crates are closer to what you actually want.

A second mismatch is the data model. bdk_chain stores and indexes chain data. That is right for a wallet that needs to know about a transaction's confirmations and find it again later. It is the wrong shape for an application that only wants to answer a live question, such as the current chain tip or a balance, because building an index for that is work the application did not ask for.

A third is operational. The workspace has no notion of a production persistence layer of its own, since file_store is explicitly out. Choosing where chain data actually lives is left to you, which is the right call for a library and a real burden for a small team that would rather not design a storage format.

One more practical note on versions. The release tags are per crate, and the list shows chain-0.23.2 from 2025-09-14, chain-0.23.3 from 2026-03-26 and chain-0.23.4 from 2026-10-12. Since the crates depend on each other, you are choosing a set of versions rather than one, and the README does not document a compatibility matrix for them. The last push to the repository was on 2026-10-19, so the crates move independently of their tags.

Editorial conclusion

BDK fits a Rust team building a Bitcoin wallet or any application that needs descriptor-aware key handling and chain data from a chosen backend, and it gives you a choice of esplora, electrum or bitcoind without changing the layer above. It does not fit a team that wants the whole wallet in one dependency, because the Wallet type lives in the separate bdk_wallet repository, and it does not fit anyone planning to store chain data in bdk_file_store, which the project marks as intended for testing and development. Before depending on it, read the SECURITY.md policy, check that your toolchain meets the MSRV of 1.85.0 or plan to run ci/pin-msrv.sh, and pick a version per crate, since the release tags are per crate and the most recent is chain-0.23.4 from 2026-10-12. The last push was on 2026-10-19.

Frequently asked questions

What is the difference between the BDK repository and bdk_wallet?

The bdk repository holds the lower-level mechanism crates: chain, core, esplora, electrum, bitcoind_rpc and file_store. The bdk_wallet repository and crate contain the higher level Wallet type that depends on those lower-level crates, so a full wallet takes both projects.

How do I build and test the BDK workspace?

The project uses a justfile, so you need just installed and can list the recipes by running `just`. The build recipe runs cargo build, and the test recipe runs cargo test per crate with all features enabled, for example `cargo test -p bdk_chain --all-features`. The pre-push recipe chains fmt, check and test.

What is the minimum supported Rust version for the BDK crates?

The listed crates maintain an MSRV of 1.85.0. To build them against that toolchain you need to pin dependencies by running the ci/pin-msrv.sh script.

Under which licence is the Bitcoin Dev Kit released?

Dual licensed: you may use it under the Apache License 2.0 or the MIT licence, at your option, with LICENSE-APACHE and LICENSE-MIT in the repository root. Contributions are dual licensed the same way unless they state otherwise, and security issues are reported through the policy in SECURITY.md.

Can I use bdk_file_store to persist chain data in production?

No. The architecture table describes it as a persistence backend for storing chain data in a single file, intended for testing and development purposes and not for production.

Official sources

  1. bitcoindevkit/bdk on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bitcoindevkit-bdk.svg)](https://hysenlabs.com/projects/bitcoindevkit-bdk)

Was this useful?