Introduction
Using Metaplex Core in Anchor
Last updated July 15, 2026
Build on-chain programs that interact with Core Assets using Anchor. This guide covers installation, account deserialization, plugin access, and CPI patterns.
What You'll Learn
- Install and configure mpl-core in Anchor projects
- Deserialize Core Assets and Collections in your programs
- Access plugin data (Attributes, Freeze, etc.)
- Make CPI calls to create, transfer, and manage Assets
Summary
The mpl-core Rust crate provides everything needed to interact with Core from Anchor programs. Enable the anchor feature flag for native Anchor account deserialization.
- Add
mpl-corewithdefault-features = falseand the appropriate Anchor features - Use
features = ["anchor", "anchor-0-32"]withanchor-lang 0.32.x - Use
features = ["anchor"]withanchor-lang 0.31.x - Deserialize Assets/Collections in Accounts structs
- Use
fetch_plugin()to read plugin data - CPI builders simplify instruction calls
Out of Scope
Client-side JavaScript SDK (see JavaScript SDK), standalone Rust clients (see Rust SDK), and creating Core Assets from clients.
Quick Start
Jump to: Installation · Account Deserialization · Plugin Access · CPI Examples
- Add
mpl-corewithdefault-features = falseand Anchor features toCargo.toml - Pin Rust
1.89.0or newer inrust-toolchain.toml - Deserialize Assets with
Account<'info, BaseAssetV1> - Access plugins with
fetch_plugin::<BaseAssetV1, PluginType>() - Make CPI calls with
CreateV2CpiBuilder,TransferV1CpiBuilder, etc.
Installation
Add mpl-core to your Anchor program's Cargo.toml. The default borsh-v1 feature is incompatible with Anchor integration, so always disable default features when enabling anchor.
Feature Flags
| Feature | Description |
|---|---|
anchor | Enables Anchor account deserialization using anchor-lang 0.31.1 and Solana 2.x types |
anchor-0-32 | Opt-in support for anchor-lang 0.32.x; requires anchor |
serde | Optional serde support for off-chain tooling |
Anchor 0.32.x (recommended)
Use this when your program depends on anchor-lang 0.32.x:
[dependencies]
anchor-lang = "0.32.1"
mpl-core = { version = "x.x.x", default-features = false, features = ["anchor", "anchor-0-32"] }
Anchor 0.31.x (legacy)
Use this when your program depends on anchor-lang 0.31.x:
[dependencies]
anchor-lang = "0.31.1"
mpl-core = { version = "x.x.x", default-features = false, features = ["anchor"] }
Important
anchor-0-32alone is not enough — it must be combined withanchor.default-features = falseis required. Without it, the defaultborsh-v1feature conflicts with Anchor integration.- The Anchor path uses Solana 2.x types for
Pubkey,AccountInfo, and related Anchor traits.
Rust Toolchain
mpl-core requires Rust 1.89.0 or newer. Add a rust-toolchain.toml file to your Anchor workspace:
[toolchain]
channel = "1.89.0"
If your build fails with an edition2024 error from transitive dependencies such as base64ct, upgrade to Rust 1.89.0 or newer.
Core Rust SDK Modules
The Core Rust SDK is organized into several modules:
accounts: represents the program's accounts.errors: enumerates the program's errors.instructions: facilitates the creation of instructions, instruction arguments, and CPI instructions.types: represents types used by the program. For more detailed information on how different instructions are called and used, refer to the mpl-core docs.rs website or you can usecmd + left click(mac) orctrl + left click(windows) on the instruction to expand it.
Accounts Deserialization
Deserializable Accounts
The following account structs are available for deserialization within the mpl-core crate:
- BaseAssetV1
- BaseCollectionV1
- HashedAssetV1
- PluginHeaderV1
- PluginRegistryV1
There are two ways to deserialize Core accounts within Anchor.
- Using Anchors Account list struct (recommended in most cases),
- Directly in the instruction functions body using
<Account>::from_bytes().
Anchor Accounts List Method
By activating the anchor flag you'll be able to deserialize both the BaseAssetV1 and BaseCollectionV1 accounts directly in the Anchor Accounts list struct:
Accounts Deserialization
#[derive(Accounts)]
pub struct ExampleAccountStruct<'info> {
...
pub asset: Account<'info, BaseAssetV1>,
}
Account from_bytes() Method
Borrow the data inside the asset/collection account using the try_borrow_data() function and create the asset/collection struct from those bytes:
Accounts Deserialization
let data = ctx.accounts.asset.try_borrow_data()?;
let base_asset: BaseAssetV1 = BaseAssetV1::from_bytes(&data.as_ref())?;
Deserializing Plugins
To access individual plugins within an Asset or Collection account, use the fetch_plugin() function. This function will either return the plugin data or a null response without throwing an hard error, allowing you to check if a plugin exists without having to access its data. The fetch_plugin() function is used for both Assets and Collections accounts and can handle every plugin type by specifying the appropriate typing. If you want to access the data inside a plugin, use the middle value returned by this function.
Plugins Deserialization
let (_, attribute_list, _) = fetch_plugin::<BaseAssetV1, Attributes>(&ctx.accounts.asset.to_account_info(), mpl_core::types::PluginType::Attributes)?;
Note: The fetch_plugin() function is only used for non-external plugins. To read external plugins, use the fetch_external_plugin() function, which operates in the same way as fetch_plugin().
The CPI Instruction Builders
Each instruction from the Core crate comes with a CpiBuilder version. The CpiBuilder version is created using name of the instruction + CpiBuilder and simplifies the code significantly abstracting a lot of boilerplate code away! If you want to learn more about all the possible instruction available in Core, you can find them on the mpl-core docs.rs website
CPI Example
Let's take the CreateCollectionV2CpiBuilder instruction as an example Initialize the builder by calling new on the CpiBuilder and passing in the core program as AccountInfo:
CreateCollectionV2CpiBuilder::new(ctx.accounts.mpl_core_program.to_account_info);
Use then Cmd + left click (Ctrl + left click for Windows users) to view all the CPI arguments required for this CPI call:
CreateCollectionV2CpiBuilder::new(&ctx.accounts.core_program)
.collection(&ctx.accounts.collection)
.payer(&ctx.accounts.payer)
.system_program(&ctx.accounts.system_program)
.name("Test Collection".to_string())
.uri("https://test.com".to_string())
.invoke()?;
Common Errors
AccountNotInitialized
The Asset or Collection account doesn't exist or hasn't been created yet.
PluginNotFound
The plugin you're trying to fetch doesn't exist on the Asset. Check with fetch_plugin() which returns None safely.
InvalidAuthority
The signer doesn't have permission for this operation. Verify the correct authority is signing.
Notes
- Always set
default-features = falsewhen enabling Anchor features - Use
features = ["anchor", "anchor-0-32"]withanchor-lang 0.32.x - Use
features = ["anchor"]withanchor-lang 0.31.x - Pin Rust
1.89.0or newer inrust-toolchain.toml - Use
fetch_plugin()for built-in plugins,fetch_external_plugin()for external - CPI builders abstract away account ordering complexity
- Check docs.rs/mpl-core for complete API reference
Quick Reference
Common CPI Builders
| Operation | CPI Builder |
|---|---|
| Create Asset | CreateV2CpiBuilder |
| Create Collection | CreateCollectionV2CpiBuilder |
| Transfer Asset | TransferV1CpiBuilder |
| Burn Asset | BurnV1CpiBuilder |
| Update Asset | UpdateV1CpiBuilder |
| Add Plugin | AddPluginV1CpiBuilder |
| Update Plugin | UpdatePluginV1CpiBuilder |
Account Types
| Account | Struct |
|---|---|
| Asset | BaseAssetV1 |
| Collection | BaseCollectionV1 |
| Hashed Asset | HashedAssetV1 |
| Plugin Header | PluginHeaderV1 |
| Plugin Registry | PluginRegistryV1 |
FAQ
Do I need the anchor feature flag?
Yes, for direct deserialization in Accounts structs. Without it, use from_bytes() manually. Always set default-features = false when enabling anchor.
Which Anchor version should I use?
For anchor-lang 0.32.x, use default-features = false with features = ["anchor", "anchor-0-32"]. For anchor-lang 0.31.x, use features = ["anchor"] only.
What Rust version is required?
mpl-core requires Rust 1.89.0 or newer. Pin it in rust-toolchain.toml in your Anchor project.
How do I check if a plugin exists?
Use fetch_plugin() which returns Option - it won't throw an error if the plugin doesn't exist.
Can I access external plugins (Oracle, AppData)?
Yes. Use fetch_external_plugin() instead of fetch_plugin() with the appropriate key.
Where can I find all available instructions?
See the mpl-core docs.rs instructions module.
Glossary
| Term | Definition |
|---|---|
| CPI | Cross-Program Invocation - calling one program from another |
| CpiBuilder | Helper struct for constructing CPI calls |
| BaseAssetV1 | Core Asset account struct for deserialization |
| fetch_plugin() | Function to read plugin data from accounts |
| anchor feature | Cargo feature enabling Anchor-native deserialization |
| anchor-0-32 feature | Opt-in Cargo feature for anchor-lang 0.32.x support |
Related Pages
- Anchor Staking Example - Complete staking program
- Create Asset with Anchor - Step-by-step guide
- Rust SDK - Standalone Rust client usage
- mpl-core docs.rs - Complete API reference
