alloy splits transports, signers and RPC namespaces into crates you can take one at a time
Transports, Middleware, and Networks for the Alloy project
At a glance
- What is it?
- Alloy is a Rust rewrite of ethers-rs for talking to Ethereum-compatible chains, published as a workspace of small crates so you can depend on `alloy-transport-http` alone or on the `alloy` meta-crate with optional integrations. The `full` feature is a convenience bundle rather than the maximum, and its omissions are named in the README.
- Who is it for?
- Alloy fits a Rust team building on Ethereum or a compatible chain that may want to depend on a single transport or signer crate rather than a meta-crate. Do not adopt it expecting `full` to be complete, because the README states node bindings, ENS, genesis and trie support and cloud or hardware signers stay opt-in, and do not adopt it if you cannot move to a recent Rust toolchain, since the workspace declares a `rust-version` of 1.94.1.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days 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 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The meta-crate is one option among thirty
The repository is a Cargo workspace with members declared as `crates/*`, so the crate list in the README is the actual layout rather than a documentation summary.
The entry point is `alloy`, described as the meta-crate for the entire project and including `alloy-core`. Everything else is split by concern. `alloy-provider` is the interface with a blockchain, `alloy-transport` is the low-level transport abstraction with `alloy-transport-http`, `alloy-transport-ipc` and `alloy-transport-ws` beneath it, and `alloy-rpc-client` sits below that as the low-level JSON-RPC client implementation. `alloy-json-rpc` holds the core data types for JSON-RPC 2.0 clients.
The split is by protocol concern rather than by convenience, and it goes deep. `alloy-rpc-types` is a meta-crate over a long list of namespace crates: `admin`, `anvil`, `any`, `beacon`, `debug`, `engine`, `eth`, `mev`, `tenderly`, `trace` and `txpool`. If you only need the standard Ethereum namespace you take `alloy-rpc-types-eth` and nothing else.
Ethereum improvement proposals have their own crates. `alloy-eips` implements EIPs generally, `alloy-eip5792` holds types for the `wallet_` JSON-RPC namespace, and `alloy-eip7547` covers EIP-7547 inclusion list types. Consensus is split too, with `alloy-consensus` as the Ethereum consensus interface and `alloy-consensus-any` as a catch-all for multiple networks.
On-chain interaction is `alloy-contract`, names and genesis are `alloy-ens` and `alloy-genesis`, execution-layer client bindings are `alloy-node-bindings`, subscription support is `alloy-pubsub`, and `alloy-tx-macros` provides a derive macro for transaction envelopes.
A workspace this fine-grained is only usable because Cargo features are the control surface, which is where the README spends most of its words.
full is a bundle, and the README lists what is not in it
Installation is one command, and the default feature set is deliberately modest.
cargo add alloyor `alloy = "2"` in `Cargo.toml`. The default features include contracts, an HTTP provider, Ethereum RPC types and a local signer. WebSocket and IPC transports plus commonly used extended RPC APIs come from the `full` feature:
cargo add alloy --features fullThen comes the sentence that saves people a debugging session: `full` is a convenience bundle, not every optional integration. Node process bindings, ENS, genesis and trie support, and cloud or hardware signers remain opt-in.
So a project that enables `full` and then reaches for ENS names or a node binding will find it missing, and the fix is documented in two commands:
cargo add alloy --features node-bindingsThere is a specific trap here worth naming. If you already depend on `full`, you must add `node-bindings` explicitly, because `full` does not include it:
cargo add alloy --features "full,node-bindings"Two more feature-level details. The `ProviderBuilder::connect_anvil*` helpers from the `alloy` meta-crate require `provider-anvil-node`. And if you depend on `alloy-provider` directly rather than the meta-crate, the equivalent feature there is named `anvil-node`, which is an inconsistency in naming that will send you looking at docs.rs when you assumed the two were the same flag.
The README's advice for anything beyond this is to enable only the features you need or depend on the individual crates directly, and points at the feature list on docs.rs and at the `alloy` crate's `Cargo.toml` as the authority.
Connecting is a builder, and network genericity is the type system
The connection example is short enough to read as the intended shape of a client.
use alloy::providers::{Provider, ProviderBuilder};
# async fn example() -> Result<(), Box<dyn std::error::Error>> {
// Create a provider with the HTTP transport using the `reqwest` crate.
let rpc_url = "https://eth.llamarpc.com";
let provider = ProviderBuilder::new().connect(rpc_url).await?;
// Get the latest block number.
let latest_block = provider.get_block_number().await?;
println!("Latest block number: {latest_block}");
// Get chain ID.
let chain_id = provider.get_chain_id().await?;
println!("Chain ID: {chain_id}");
# Ok(())
# }The builder takes no arguments and the URL is passed to `connect`. Note the comment naming `reqwest` as the HTTP implementation, which means the transport crate choice is what determines your HTTP stack and its TLS.
The trait you call methods on is `Provider`, imported alongside `ProviderBuilder`, so the provider is the interface rather than a concrete type. That is what makes the network genericity real rather than nominal.
Alloy is described as network-generic, meaning you can work with any Ethereum-compatible chain, and the mechanism is a type parameter on the builder rather than a runtime configuration value. The Optimism example uses `new_with_network::<Optimism>()`:
use alloy::providers::{Provider, ProviderBuilder};
use op_alloy::network::Optimism;
# async fn example() -> Result<(), Box<dyn std::error::Error>> {
// Connect to Optimism mainnet.
let rpc_url = "https://mainnet.optimism.io";
let provider = ProviderBuilder::new_with_network::<Optimism>().connect(rpc_url).await?;
# Ok(())
# }The Optimism network type comes from a separate crate, `op-alloy`, so chain-specific types are external rather than baked in. That is a clean separation: the core does not accumulate chain forks, and each chain opts in by providing a network type that maps chain-specific RPC responses onto the shared primitives.
More examples live in a separate examples repository rather than in this one.
Signers are the part to check before you commit
The signer list is the most security-relevant part of the crate map, and it is worth reading item by item rather than as a menu.
`alloy-signer` is the abstraction. `alloy-signer-local` covers the cases where a private key exists on your machine: private key, keystore, mnemonic, and YubiHSM. That single crate handles four very different trust models, which is a convenience and a reason to look at exactly which constructor you are calling.
Hardware signers have their own crates: `alloy-signer-ledger` and `alloy-signer-trezor`. Cloud key management has three: `alloy-signer-aws` for AWS KMS, `alloy-signer-azure` for Azure Key Vault and `alloy-signer-gcp` for GCP KMS. `alloy-signer-turnkey` is a separate signer implementation.
One entry is different in kind and worth not skimming. `alloy-signer-tempo` is described as a read-only Tempo wallet keystore lookup that materializes local signers, so it reads a keystore from somewhere else and produces local signers from it, which is a different trust boundary from a cloud KMS call where the key never leaves.
Combined with the feature discussion above, this gives a concrete adoption check: the cloud and hardware signers are exactly the categories the README says stay opt-in even under `full`. Enabling `full` does not give you KMS, Ledger or Trezor support. If your deployment signs with a cloud KMS, you are adding a signer crate and reviewing its dependency tree yourself.
The wallet namespace types are also separated out, in `alloy-eip5792`, which is where the `wallet_` JSON-RPC methods live. That is relevant if you rely on those methods, since they are the newer account abstraction style entry point rather than `eth_sendRawTransaction`.
Workspace lint rules and the toolchain floor
The workspace manifest documents how the project holds itself to a standard, and the rules are stricter than a default.
The lint table sets `unused_must_use` to `deny` rather than `warn`, which is the one rule that fails a build rather than producing a warning, and it denies the 2018 idioms set at priority minus one so that individual overrides can take priority. `missing_debug_implementations`, `missing_docs`, `unreachable_pub` and `unnameable_types` are all warnings, as is the full rustdoc lint set at `all = "warn"`, so documentation is treated as a linted surface.
The clippy configuration warns on `all` plus `missing_const_for_fn`, `use_self` and `redundant_clone`, and explicitly allows `large_enum_variant` and `result_large_err`, which are two lints a performance-sensitive networking library would normally trip. Those two allows are informative: they say the library knowingly carries large enum variants and large error types for throughput reasons.
The toolchain requirement is stated in the manifest as `rust-version = "1.94.1"`, with edition 2021 and resolver version 2. A patch-level floor that specific is unusual and worth checking against your toolchain before anything else, since a dependency that requires a newer Rust than you can install is a hard stop rather than a warning.
The workspace declares `license = "MIT OR Apache-2.0"`, and the repository root carries both `LICENSE-APACHE` and `LICENSE-MIT` files. The dual licence is the standard Rust convention and lets you choose either, so a proprietary product can take MIT and avoid any Apache patent-grant clause interaction with your licensing policy.
Supporting files describe the release process rather than the code: `CHANGELOG.md`, `RELEASE_CHECKLIST.md`, `cliff.toml` for changelog generation, `release.toml` and `deny.toml` for dependency policy, `rustfmt.toml` and `typos.toml` for formatting and spell checking, and a `FUNDING.json`.
Maintenance is current. The repository is not archived, the last push was on 2026-10-15, two days before today, and The listed releases include v2.5.0 on 2026-09-23, v2.4.2 on 2026-09-08 and v2.4.1 on 2026-08-13.
Against ethers-rs, and where the cost sits
Alloy describes itself as a rewrite of ethers-rs from the ground up with new features and performance, and that framing determines the comparison.
For an existing ethers-rs user, the README calls Alloy a rewrite from the ground up but does not establish API parity. If your application already builds on ethers-rs, the migration story is whether the calls you use exist under the same names, and the crate split above suggests a good deal of surface is equivalent. The README's own comparison is thin on specifics, so anyone migrating should check the docs rather than assume parity in either direction.
Against a raw JSON-RPC client, the difference is that Alloy carries Ethereum's type system. Block numbers, transaction envelopes, receipts and log filters are typed values rather than JSON maps you assemble yourself. That is the whole value: an RPC call you can get wrong in one direction returns an error, and in the other direction returns a struct that cannot represent an invalid block. The cost is compile time and a dependency tree far larger than an HTTP client.
Three cases argue against it. If you need a chain that is only loosely Ethereum-compatible and does not follow the JSON-RPC shape Alloy models, you are fighting the type system. If your deployment is in an environment where a recent Rust toolchain is not available, the 1.94.1 floor rules it out. And if you need exactly one thing, such as subscribing to logs over a WebSocket, depending on the single transport crate rather than the meta-crate is markedly cheaper and the README points you at doing exactly that.
That last point is the one worth internalising. The workspace layout is not an implementation detail, it is the feature. Teams that take the meta-crate for convenience and then need a signer they did not enable will find the documented route is to add a specific feature or drop to a specific crate.
Editorial conclusion
Alloy fits a Rust team building on Ethereum or a compatible chain that may want to depend on a single transport or signer crate rather than a meta-crate. Do not adopt it expecting `full` to be complete, because the README states node bindings, ENS, genesis and trie support and cloud or hardware signers stay opt-in, and do not adopt it if you cannot move to a recent Rust toolchain, since the workspace declares a `rust-version` of 1.94.1. Verify first which signer you need and whether it is in the set the feature set you enabled actually includes.
Frequently asked questions
How do I add alloy to a Rust project?
Run `cargo add alloy`, or add `alloy = "2"` to Cargo.toml. The default features include contracts, an HTTP provider, Ethereum RPC types and a local signer. Add `--features full` for WebSocket and IPC transports plus common extended RPC APIs.
Does the full feature include everything?
No. The README states `full` is a convenience bundle rather than every optional integration: node process bindings, ENS, genesis and trie support, and cloud or hardware signers remain opt-in. If you already depend on `full`, add `node-bindings` explicitly because `full` does not include it.
Which Rust version does alloy require?
The workspace manifest declares `rust-version = "1.94.1"` with edition 2021. That is a hard floor, so a toolchain older than it cannot build the workspace.
Which hardware and cloud signers does alloy support?
Hardware signers have `alloy-signer-ledger` and `alloy-signer-trezor`. Cloud key management has `alloy-signer-aws`, `alloy-signer-azure` and `alloy-signer-gcp`, plus `alloy-signer-turnkey`. `alloy-signer-local` handles private key, keystore, mnemonic and YubiHSM, and `alloy-signer-tempo` is a read-only wallet keystore lookup that materializes local signers.
How do I connect to a non-Ethereum chain such as Optimism?
Alloy is network-generic and the network is a type parameter on the builder rather than a runtime value. `ProviderBuilder::new_with_network::<Optimism>()` connects to Optimism mainnet, with the `Optimism` network type coming from the separate `op-alloy` crate.
What license is alloy released under?
Dual licensed, MIT OR Apache-2.0, declared in the workspace manifest with `LICENSE-APACHE` and `LICENSE-MIT` at the repository root. The dual licence is the standard Rust convention and lets a proprietary project take the MIT option.
Official sources
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.
[](https://hysenlabs.com/projects/alloy-rs-alloy)Was this useful?