# fuel-core: one Rust workspace, thirty service crates, and three versions in its own docs

> FuelLabs/fuel-core is the Rust full node for the Fuel v2 protocol, assembled as a Cargo workspace of roughly thirty crates and launched with a single fuel-core run. What an operator meets before any of that is a version question the project answers three different ways: the network table says 0.48.1, the build-from-source section checks out v0.45.1, and the sample log prints v0.18.1.

**FuelLabs/fuel-core** — Rust full node implementation of the Fuel v2 protocol.

- Repository: https://github.com/FuelLabs/fuel-core
- Stars: 56,824 · Forks: 2,862
- Language: Rust
- License: NOASSERTION
- Published: 2026-08-17 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/fuellabs-fuel-core

## The workspace lists every service a node is made of, from bft to txpool_v2

fuel-core is a node, and the Cargo.toml shows what a node is made of here. The workspace is edition 2024 with rust-version 1.94.1, and its members include separate crates for the pieces a chain client actually needs: consensus in two flavours, bft and poa, an executor and a parallel-executor, a producer, an importer and a sync service, p2p, txpool_v2, a gas_price_service, a relayer, a shared-sequencer, an upgradable-executor with a wasm-executor inside it, and a tx_status_manager.

Underneath sit the storage and type layers, crates/database, crates/storage, crates/types, crates/trace and crates/syscall, plus crates/client and crates/provider for the API side and crates/metrics. The binary itself is bin/fuel-core, and bin/fuel-core-client sits next to it alongside bin/keygen, bin/chaos-test and bin/e2e-test-client. There is a separate version-compatibility directory that the workspace explicitly excludes, which is where cross-version checks live. Two things stand out for a reader: consensus is a choice you make at build time between bft and poa, and the executor is versioned separately from the services around it.

## make build for a binary, cargo xtask build for a working copy

There are three build entry points in the repository, and the Makefile is the one operators are pointed at. Its targets are short and worth reading before you run anything:

```bash
make build
```

runs cargo build-fuel-core-bin-release, while make debug runs cargo build-fuel-core-bin, make test runs cargo nextest run --all-targets --all-features, make fmt runs cargo +nightly fmt, and make ci-checks runs ./ci_checks.sh. A Makefile.toml sits next to the Makefile for cargo make, so the same repository answers to both tools.

Contributors are told to use a third route, and the difference matters:

```bash
cargo xtask build
```

That runs cargo build and also the custom build steps, including regenerating the GraphQL schema for the client. So a release binary from make build and a development copy from cargo xtask build are not the same artefact, and the one you want depends on whether you intend to serve the API. For running a local node the README is explicit about which to use: clone, make build, then follow the local node guide on docs.fuel.network.

## clang, cmake and a wasm32 target stand between a clone and a binary

The build needs a C toolchain, and the project gives per-platform package lists rather than a single instruction. On macOS:

```bash
brew update
brew install cmake
```

On Debian and Ubuntu:

```bash
apt update
apt install -y cmake pkg-config build-essential git clang libclang-dev
```

Arch has its own line with cmake, gcc, pkgconf, git and clang. Then there is the Rust target, which is not optional because the executor runs WebAssembly:

```bash
rustup target add wasm32-unknown-unknown
```

A rust-toolchain.toml at the repository root pins the toolchain, so a plain clone and build takes whichever version that file names rather than your default. With those in place the binary comes from make build, and the debug binary, which is what the documentation's own examples invoke, is ./target/debug/fuel-core. Two smaller prerequisites are easy to miss: the ci_checks.sh script expects tools already installed on the machine, and the debugging guide at docs/developers/debugging.md assumes a debug build of a local node rather than a release one.

## --db-type in-memory decides whether the node keeps anything at all

The service starts with fuel-core run, and the three flags the documentation demonstrates are the ones that decide what kind of node you have. The help output shows the shape of it:

```console
$ ./target/debug/fuel-core run --help

USAGE:
    fuel-core run [OPTIONS]

OPTIONS:
        --snapshot <SNAPSHOT>
          Snapshot from which to do (re)genesis. Defaults to local testnet configuration

          [env: SNAPSHOT=]
        ...
```

Setting --db-type to in-memory gives you a node whose state does not persist, which is the point for development: you get a clean chain on every start. Block production is instant by default, and --poa-instant=false turns it off, which is what you want when you want to submit blocks yourself. The snapshot option, also readable from a SNAPSHOT environment variable, decides where genesis or re-genesis begins, and it defaults to a local testnet configuration rather than to a mainnet state.

Two environment variables shape what you see rather than what the node does. RUST_LOG controls the tracing filter, and HUMAN_LOGGING=false turns off the human-readable log output the service produces by default. A successful in-memory start ends with the GraphQL provider bound, which is the line to look for.

## The network table says 0.48.1, the checkout says v0.45.1, the log says v0.18.1

This is the part to read twice. The table of versions currently used in networks lists 0.48.1 for Fuel Ignition, for Testnet and for Devnet, all three the same. The newest release tag is v0.48.3, published on 2026-08-27, and the workspace Cargo.toml carries version 0.48.3, matching the tags v0.48.2 and v0.48.1 beneath it. The last push to master was on 2026-09-27 and the repository is not archived, so the code is moving.

Then the build-from-source section says to go to the latest release tag for Ignition and gives one specific command, git checkout v0.45.1, which is three patch releases behind the version the table says the network runs. And the sample console output in the running section prints Fuel Core version v0.18.1, an order of magnitude older again, alongside log lines dated 2023-06-13.

None of this means the code is wrong, and the v0.18.1 line is plainly a captured log rather than a claim. But an operator who copies the checkout command gets a node that is not the version the table names, and the documentation offers no way to tell which instruction to believe. Checking the network's expected version before you build is the step the README should have made and did not.

## Column families not opened is what a stale RocksDB looks like, and the fix deletes it

Change the code under a node that already has a database and the node will refuse to start with a panic rather than a readable error:

```console
thread 'main' panicked at 'unable to open database: DatabaseError(Error { message: "Invalid argument: Column families not opened: column-11, column-10, column-9, column-8, column-7, column-6, column-5, column-4, column-3, column-2, column-1, column-0" })', fuel-core/src/main.rs:23:66
```

The documented recovery is to clear the local database with rm -rf ~/.fuel/db. That is the whole fix, and it is destructive: everything the node had written, including anything a local test produced, is gone with it. There is no migration path described for the local case, only deletion.

The second failure mode is quieter and shows up mostly on macOS, where the default file descriptor limit is low enough that RocksDB fails with Too many open files, or with fatal runtime error: Rust cannot catch foreign exceptions when it hits the same wall. The fix is to raise the limit for the shell session:

```bash
ulimit -n 10240
```

That change is not persistent, so it has to go into ~/.zshrc if you want it to survive a new terminal, and until you do it the node fails in a way that reads like a crash in the runtime rather than an exhausted resource.

## docker-compose.yml publishes one port and mounts one volume

The container route is two commands and a compose file. The image is built from a Dockerfile in the deployment directory with the repository root as context:

```bash
docker build -t fuel-core . -f deployment/Dockerfile
```

The compose file in the repository root declares version 3.9, builds that same image, and gives the service exactly one published port and one volume:

```bash
kubectl create -f deployment/fuel-core.yml
```

The port is 4000, which is the GraphQL endpoint the node binds, and the volume is mounted at /mnt/db, which is where the database has to live for the mount to be useful. Nothing else is wired up. The workspace contains a crates/metrics member, and this compose file declares no port for it, so scraping a container started from it is something you add yourself. A Kubernetes route is documented in the same section, creating and deleting the volume, deployment and service from deployment/fuel-core.yml.

For anything beyond a local node, note that the node's own documentation is external. The README links out to docs.fuel.network for the mainnet node and the local node procedures rather than describing them here, so the parts that decide persistence, snapshots and networking for a real network live outside this repository.

## source ci_checks.sh is the gate, and publishing runs through a GitHub action

The contribution rule is short and absolute: before pushing any changes or creating a pull request, run the checks script.

```bash
source ci_checks.sh
```

It runs all the CI checks including the tests, and it needs tools that are expected to be installed already, which is why the documentation tells you to read it with cat ci_checks.sh before you run it. The same work is available as make ci-checks and make test, where the test target is cargo nextest run --all-targets --all-features. Coding standards and the review process live in CONTRIBUTING.md, and the repository also carries an AGENTS.md, a SECURITY.md and a .policy.yml alongside the usual CI configuration.

Releases are published automatically for all crates by a publish-crates GitHub action, and there is a documented way to rehearse that locally with act, which needs a GitHub token:

```bash
act release -s GITHUB_TOKEN=<YOUR_GITHUB_TOKEN> -j publish-crates-check --container-architecture linux/amd64 --reuse
```

That is the whole release path a contributor can touch. If your problem is a publish that fails partway, the documentation sends you to this command rather than to a local dry run, so a fork is debugging someone else's workflow with someone else's credentials.

## Conclusion

fuel-core suits an operator who wants to read a node in Rust rather than configure a black box, and who can afford the toolchain: clang, cmake, a wasm32 target and a Rust release matching rust-version 1.94.1. Do not follow its version guidance literally, because the tag it tells you to check out is three patch releases behind the version its network table names. Before you commit to it, confirm two things: that the version you run is the one your network expects, since Ignition, Testnet and Devnet are all listed at 0.48.1 while the workspace sits at 0.48.3, and what the licence permits, since Cargo.toml declares BUSL-1.1 with the terms left to the LICENSE file at the repository root.

## FAQ

### How do I build fuel-core from source?

Clone the repository, install the system packages for your platform including clang and cmake, add the Rust target with rustup target add wasm32-unknown-unknown, and run make build, which calls cargo build-fuel-core-bin-release. Contributors are pointed at cargo xtask build instead, because it also regenerates the GraphQL schema for the client.

### Which fuel-core version runs on the Fuel networks?

The network table in the project's documentation lists 0.48.1 for Fuel Ignition, Testnet and Devnet. The workspace Cargo.toml and the newest release tag are both at 0.48.3, published on 2026-08-27, so the version to run is the one your network expects rather than the newest tag.

### What does fuel-core run --db-type in-memory do?

It starts a node whose state is not persisted, which the documentation describes as useful when you want a chain that does not survive between runs. Block production is instant by default and can be turned off with --poa-instant=false, and the --snapshot option chooses where genesis or re-genesis starts from, defaulting to a local testnet configuration.

### Where is the fuel-core GraphQL endpoint and its schema?

The client is reached at the service endpoint /v1/graphql, and the schema is written to crates/client/assets/schema.sdl once you have built the workspace. The service expects a mutation named submit that receives a transaction in hex encoded binary format.

### What licence does fuel-core use?

The workspace Cargo.toml declares license as BUSL-1.1 and the terms live in the LICENSE file at the repository root, while the repository metadata itself reports no asserted licence. The project documentation does not restate what those terms permit, so the file is the only statement of what you may do with the code.

## Sources

- [Official README](https://github.com/FuelLabs/fuel-core#readme)
- [Project repository](https://github.com/FuelLabs/fuel-core)
- [Release notes](https://github.com/FuelLabs/fuel-core/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fuellabs-fuel-core
