NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #4221 most downloaded on crates.io
A no-std compatible subset of Subxt's functionality
Last release 6 months ago
12 Mar 2026
Release timing varies
gaps range from 2 weeks to 5 months
Most releases are documented
notes for 12 of 17 stable releases
1 version withdrawn
withdrawn after publishing
3 years old
18 releases · first in 2024
Nothing published for this version
This manually cherry-picks #2142 onto the 0.44 branch to allow using $OUT_DIR in a couple of Subxt macro attributes.
When using .tip_of(some_tip, optional_asset_id) to configure a tip for transactions, the actual tip was being set to 0. This is now fixed.
One column per month.
When using .tip_of(some_tip, optional_asset_id) to configure a tip for transactions, the actual tip was being set to 0. This is now fixed.
This is a minor version bump because, in theory at least, adding the Clone bound to block headers in ( #2047 ) is a breaking change, although I think…
This small release primarily fixes a few issues, but also adds the code for a prelease of subxt-historic, a new crate (at the moment) for working with historic blocks and state. Future releases will aim to stabilize this crate to the level of other subxt crates or otherwise merge the logic into subxt itself.
This is a minor version bump because, in theory at least, adding the Clone bound to block headers in (#2047) is a breaking change, although I think it is unlikely that this will impact any users.
subxt-historic crate for accessing historic (non head-of-chain) blocks (#2040)This is a reasonably small release which is mainly bug fixing, but has a couple of changes I'd like to elaborate on:
This is a reasonably small release which is mainly bug fixing, but has a couple of changes I'd like to elaborate on:
codec::Encode and codec::Decode derives from generated APIs by default (#2008)When generating an API using the #[subxt::subxt(...)] macro (or programatically via subxt-codegen), we had always previously added parity_scale_codec::Encode and parity_scale_codec::Decode derives to all of the generated types. Most places in Subxt have not made use of these for a long time (relying instead on scale_encode::EncodeAsType and scale_decode::DecodeAsType, since they allow encoding and encoding which takes the type information into account and can more gracefully handle incompatibilities).
We eventually hit an issue to which the most appropriate fix was just to remove these derives.
If you still need the parity_scale_codec::Encode or parity_scale_codec::Decode derives on certain types, you have two options:
derive_for_type attr to add them back where needed, eg:
#[subxt::subxt(
...
derive_for_type(
path = "staging_xcm::v3::multilocation::MultiLocation",
derive = "parity_scale_codec::Encode, parity_scale_codec::Decode",
recursive
)
)]derive_for_all_types attr to add them back everywhere, eg:
#[subxt::subxt(
...
derive_for_all_types = "parity_scale_codec::Encode, parity_scale_codec::Decode"
)]
Prefer (1) where possible to reduce the amount of generated code, and reduce the likelihood of running into issues around those derives in certain edge cases.
This PR changes some things around storage keys to remove one last requirement for Encode and Decode derives, and also as a side effect changes api.storage().call_raw() slightly to no longer also try to decode the resulting type via Decode, leaving this to the user (and also meaning it's much easier now for the user to obtain the raw bytes for some storage entry).
In other words, instead of doing something like:
let (compact_len, metadata) = rt
.call_raw::<(Compact<u32>, frame_metadata::RuntimeMetadataPrefixed)>(
"Metadata_metadata",
None,
)
.await?;You would now do:
let meta_bytes = rt.call_raw("Metadata_metadata", None).await?;
let (compact_len, metadata): (Compact<u32>, frame_metadata::RuntimeMetadataPrefixed) =
Decode::decode(&mut &*meta_bytes)?;Prior to this change, the intended behavior was that any transaction submitted via an OnlineClient would have a mortality of 32 blocks by default, and any transaction submitted via an OfflineClient would be immortal by default. A couple of issues were present or cropped up however:
PolkadotExtrinsicParamsBuilder::new().mortal(32).build(), the OfflineClient transaction would still be immortal, because it didn't have enough information to properly configure the mortality as asked for (by virtue of being offline and unable to fetch it).OnlineClient by default, unless mortality was explicitly configured.OfflineClient transaction; you'd have to do something like this:
let params = DefaultExtrinsicParamsBuilder::new();
params.5 = CheckMortalityParams::mortal_from_unchecked(for_n_blocks, from_block_n, from_block_hash);With this PR, transactions are now mortal by default using the OnlineClient, we now return an error if you try to construct a transaction with the OfflineClient and try to use params.mortal(..) when configuring it, and we expose params.mortal_from_unchecked(..) to allow configuration for offline transactions without the ugly code above.
In this PR, we also discovered an issue decoding Eras and fixed this, so that decoding the mortality of a transaction when it is mortal should now work.
I'd like to do a quick shoutout to @wassimans, who submitted an excellent example for how to interact with Subxt via the C FFI in Python and Node.JS. This is something I've wanted to add for a while, so it's lovely to see this new example which highlights one of the strengths of Subxt over Javascript based compatitors in the space.
All of the non-trivial changes in this release are listed below:
codec::Encode and codec::Decode derives from generated APIs by default (#2008)at_latest (#2035)This patch release reduces the rust-version to 1.85.0, given that we don't use any features newer than this at the moment.
This patch release reduces the rust-version to 1.85.0, given that we don't use any features newer than this at the moment.
The primary benefit of this release is introducing support for the _about-to-be-stabilised-in-polkadot-sdk_ V16 metadata, and with that, support for c
The primary benefit of this release is introducing support for the about-to-be-stabilised-in-polkadot-sdk V16 metadata, and with that, support for calling Pallet View Functions on runtimes which will support this. Pallet View Functions are used much like Runtime APIs, except that they are declared in specific pallets and not declared at the runtime-wide level, allowing pallets to carry their own APIs with them.
Calling a Pallet View Function in this Subxt release will look like:
use runtime::proxy::view_functions::check_permissions::{Call, ProxyType};
// Construct the call, providing the two arguments.
let view_function_call = runtime::view_functions()
.proxy()
.check_permissions(
Call::System(runtime::system::Call::remark { remark: b"hi".to_vec() }),
ProxyType::Any
);
// Submit the call and get back a result.
let _is_call_allowed = api
.view_functions()
.at_latest()
.await?
.call(view_function_call)
.await?;
Like Runtime APIs and others, the dynamic API can also be used to call into Pallet View Functions, which has the advantage of not needing the statically generated interface, but the downside of not being strongly typed. This looks like the following:
use scale_value::value;
let metadata = api.metadata();
// Look up the query ID for the View Function in the node metadata:
let query_id = metadata
.pallet_by_name("Proxy")
.unwrap()
.view_function_by_name("check_permissions")
.unwrap()
.query_id();
// Construct the call, providing the two arguments.
let view_function_call = subxt::dynamic::view_function_call(
*query_id,
vec![
value!(System(remark(b"hi".to_vec()))),
value!(Any())
],
);
// Submit the call and get back a result.
let _is_call_allowed = api
.view_functions()
.at_latest()
.await?
.call(view_function_call)
.await?;
Config traitAnother change to be aware of is that our Config trait has been tweaked. The Hash associated type is no longer needed, as it can be obtained via the Hasher associated type already, and PolkadotConfig/SubstrateConfig now set the hasher by default to be DynamicHasher256, which will (when V16 metadata is available for a runtime) automatically select between Keccak256 and BlakeTwo256 hashers depending on what the chain requires.
We also solidify our support for V1 archive RPCs, upgrade the codebase to Rust 2024 edition, and a bunch of other changes, the full list of which is here:
This release makes two main changes:
This release makes two main changes:
subxt-rpcs crate.Previously, if you wanted to make raw RPC calls but weren't otherwise interested in using the higher level Subxt interface, you still needed to include the entire Subxt crate.
Now, one can depend on subxt-rpcs directly. This crate implements the new RPC-V2 chainHead/transaction endpoints as well as the currently unstable archive endpoints. it also implements various legacy endpoints that Subxt uses as a fallback to the modern ones. It also provides several feature gated clients for interacting with them:
jsonrpsee based RPC client for connecting to individual RPC nodes.jsonrpsee based client which handles reconnecting automatically in the event of network issues.Custom clients can be implemented if preferred.
Example usage via jsonrpsee feature:
use subxt_rpcs::{RpcClient, ChainHeadRpcMethods};
// Connect to a local node:
let client = RpcClient::from_url("ws://127.0.0.1:9944").await?;
// Use chainHead/archive V2 methods:
let methods = ChainHeadRpcMethods::new(client);
// Call some RPC methods (in this case a subscription):
let mut follow_subscription = methods.chainhead_v1_follow(false).await.unwrap();
while let Some(follow_event) = follow_subscription.next().await {
// do something with events..
}
Subxt has supported decoding V5 transactions from blocks since 0.38.0, but now it also supports constructing V5 transactions where allowed. Some naming changes have also taken place to align with the Substrate terminology now around transactions (see #1931 for more!).
The main changes here are:
subxt_core now contains versioned methods for creating each of the possible types of transaction (V4 unsigned, V4 signed, V5 "bare" or V5 "general"), enabling the APIs to be tailored for each case.subxt exposes higher level wrappers these (ie api.tx().create_v4_unsigned(..), api.tx().create_v5_bare(..)), but also continues to expose the same standard APIs for creating transactions which will, under the hood, decide what to create based on the chain we're connected to.sign_and_submit now take a T::AccountId rather than a T::Address since it was found to not be useful to provide the latter, and V5 transactions only expect an T::AccountId.VerifySignature).A full list of the relevant changes is as follows:
runtime-wasm-path (#1936)Nothing published for this version
This release reverts the usage of the polkadot-sdk umbrella crate, which was causing issues such as an increased number of dependencies in Cargo.lock.
This release reverts the usage of the polkadot-sdk umbrella crate, which was causing issues such as an increased number of dependencies in Cargo.lock. For more details, see #1925.
Additionally, this update bumps the Polkadot SDK-related dependencies to their latest versions, ensuring compatibility and stability.
Full Changelog: https://github.com/paritytech/subxt/compare/v0.39.0...v0.40.0
This release is mostly bug fixes and changes. The only change that should be a breaking change is removing the substrate-compat feature flag (see #185…
This release is mostly bug fixes and changes. The only change that should be a breaking change is removing the substrate-compat feature flag (see #1850), which we'll go into more detail about.
substrate-compat feature flag has been removed.The substrate-compat feature flag essentially provided:
subxt::config::Header trait for anything implementing sp_runtime::traits::Header (here).subxt::config::Hasher and anything implementing sp_runtime::traits::Hasher (here).subxt_core::tx::PairSigner type which could be given something implementing sp_core::Pair and then be used to sign transactions (here).sp_runtime::AccountId32 and related for subxt::utils::AccountId32 (here).sp_runtime::MultiAddress and subxt::utils::MultiAddress (here).sp_runtime::MultiSignature and subxt::utils::MultiSignature (here).While useful, providing these features in Subxt is almost impossible to maintain: we can only support a single version of sp_runtime/sp_core at a time, but many versions are in use in the wild. This led to various issues regarding the mismatch between sp_* crates in use and a given version of Subxt. More generally, the goal of Subxt is to be independent from any specific version of Substrate, and communicate via the exposed RPC APIs in order to work across any compatible Substrate version (or indeed, alternative implementations that follow things like the RPC spec).
As a result, we've taken the decision to remove this compatibility layer from Subxt itself. To migrate away from this feature, we suggest:
subxt_signer instead, if it's a viable alternative in your case.// Wrap a substrate header type in this to impl the subxt Header trait:
struct SubxtHeader<T>(pub T);
// This basically copies the code removed from Subxt, but on a wrapper type:
impl <T> subxt::config::Header for SubxtHeader<T>
where
T: sp_runtime::traits::Header,
<T as sp_runtime::traits::Header>::Number: Into<u64>,
{
type Number = T::Number;
type Hasher = T::Hashing;
fn number(&self) -> Self::Number {
*self.0.number()
}
}
The hope is that this pattern is applicable to any such types that you find useful to share between Substrate and Subxt code. Please raise an issue if you can't find a solution in your case, and we'll endeavour to help!
The result of this is that your code will work against whichever Substrate crate versions you are using, at the cost of this code no longer being included behind the substrate-compat feature flag.
A full list of relevant changes and fixes (nothing was added in this release) is as follows:
thiserror (#1856)jsonrpsee in subxt::ext (#1843)Nothing published for this version
This release doesn't introduce any substantial breaking changes and focuses primarily on incremental improvements, testing and bug fixes. A few of the…
This release doesn't introduce any substantial breaking changes and focuses primarily on incremental improvements, testing and bug fixes. A few of the highlights include:
subxt::backend::unstable::UnstableBackend (it's now called subxt::backend::chain_head::ChainHeadBackend). This backend can be used to interact with the modern chainHead RPC methods exposed by Smoldot and compliant RPC nodes. See this example.reconnecting-rpc-client. See this example.#[subx(runtime_path = "path/to/runtime.wasm")]).subxt-core. See this example.The notable changes in this release are as follows:
secret_key method for ecdsa::Keypair and eth::Keypair (#1628)scale family crates, primitive-types and impl-serde (#1832)instant with web-time (#1830)?Sized bound and replace never type with () (#1758)Backend impl (#1751)unstable-reconnecting-rpc-client (#1711)reconnecting-jsonrpsee-ws-client with subxt-reconnecting-rpc-client (#1705)defalt-feature -> default-features Cargo.toml (#1828)#[codec(dumb_trait_bound)] (#1630)Nothing published for this version
This release mainly adds support for the sign extension CheckMetadataHash and fixes a regression introduced in v0.36.0 where the type de-duplication w
This release mainly adds support for the sign extension CheckMetadataHash and fixes a regression introduced in v0.36.0
where the type de-duplication was too aggressive and lots of the same type such as BoundedVec was duplicated to
plenty of different types such as BoundedVec1, BoundedVec2, .. BoundedVec<N>.
Yanked because the typegen changed, it's a breaking change.
Yanked because the typegen changed, it's a breaking change.
A breaking change that comes from migrating a bunch of logic to this new crate is that the ExtrinsicParams trait is now handed &ClientState rather tha…
This release adds a few new features, which I'll go over below in more detail.
subxt-coreWe now have a brand new subxt-core crate, which is #[no-std] compatible, and contains a lot of the core logic that is needed in Subxt. Using this crate, you can do things in a no-std environment like:
blocks: decode and explore block bodies.constants: access and validate the constant addresses in some metadata.custom_values: access and validate the custom value addresses in some metadata.metadata: decode bytes into the metadata used throughout this library.storage: construct storage request payloads and decode the results you'd get back.tx: construct and sign transactions (extrinsics).runtime_api: construct runtime API request payloads and decode the results you'd get back.events: decode and explore events.Check out the docs for more, including examples of each case.
A breaking change that comes from migrating a bunch of logic to this new crate is that the ExtrinsicParams trait is now handed &ClientState<T> rather than a Client. ClientState is just a concrete struct containing the state that one needs for things like signed extensions.
We've baked in a bunch of support for automatically reconnecting after a connection loss into Subxt. This comes in three parts:
unstable-reconnecting-rpc-client feature flag at the moment, andDisconnectedWillReconnect error to the user where it cannot. Note that the individual LegacyRpcMethods and UnstableRpcMethods are not automatically retried on reconnection. Which leads us to..subxt::backend::retry and subxt::backend::retry_stream) which can be used in conjunction with a reconnecting RPC client to make it easy to automatically retry RPC method calls where needed.We'd love feedback on this reconnecting work! To try it out, enable the unstable-reconnecting-rpc-client feature flag and then you can make use of this like so:
use std::time::Duration;
use futures::StreamExt;
use subxt::backend::rpc::reconnecting_rpc_client::{Client, ExponentialBackoff};
use subxt::{OnlineClient, PolkadotConfig};
// Generate an interface that we can use from the node's metadata.
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
pub mod polkadot {}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new client with a reconnecting RPC client.
let rpc = Client::builder()
// We can configure the retry policy; here to an exponential backoff.
// This API accepts an iterator of retry delays, and here we use `take`
// to limit the number of retries.
.retry_policy(
ExponentialBackoff::from_millis(100)
.max_delay(Duration::from_secs(10))
.take(3),
)
.build("ws://localhost:9944".to_string())
.await?;
// Use this reconnecting client when instantiating a Subxt client:
let api: OnlineClient<PolkadotConfig> = OnlineClient::from_rpc_client(rpc.clone()).await?;
Check out the full example here.
We've added built-in support for Ethereum style chains (eg Frontier and Moonbeam) in subxt-signer, making it easier to sign transactions for these chains now.
Check out a full example here.
We plan to improve on this in the future, baking in better Ethereum support if possible so that it's as seamless to use AccountId20 as it is AccountId32.
A bunch of the new RPCs are now stable in the spec, and have consequently been stabilized here, bringing the unstable-backend a step closer to being stabilized itself! We'll probably first remove the feature flag and next make it the default backend, in upcoming releases.
All of the notable changes in this release are as follows:
frontier/ethereum example (#1557)subxt-core crate (#1466)scale-type-resolver 0.2 (#1565)subxt-signer::eth (#1553)Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →