LogoAnchor Docs
Anchor Project UpdatesRelease Notes

1.0.0

Anchor - Release Notes 1.0.0

1.0.0 is the first stable major release of Anchor. It ships a large number of breaking changes designed to clean up long-standing technical debt, modernize the toolchain, and establish a stable foundation going forward. We cover the most important changes below, but be sure to check out the full list of changes in the CHANGELOG.


How to upgrade

  1. Update avm itself before installing the new CLI. If your current avm supports self-update, use:

    avm self-update

    Otherwise, bootstrap using cargo install:

    cargo install avm --git https://github.com/solana-foundation/anchor --locked
  2. Update anchor-cli:

    avm install 1.0.0

Without AVM

Install anchor-cli directly:

cargo install --git https://github.com/solana-foundation/anchor --tag v1.0.0 anchor-cli --locked

Common steps

  1. Update Anchor crate(s) to 1.0.0.

  2. Update TS package(s). Note that the package has been renamed — see TypeScript package rename below.

The recommended Solana version is 3.1.10.

You can install the newer tooling by running:

sh -c "$(curl -sSfL https://release.anza.xyz/v3.1.10/install)"

Breaking Changes

TypeScript package rename

The TypeScript package has been moved from @coral-xyz/anchor to @anchor-lang/core:

npm install @anchor-lang/core

Update every import in your project:

- import * as anchor from "@coral-xyz/anchor";
- import { Program } from "@coral-xyz/anchor";
+ import * as anchor from "@anchor-lang/core";
+ import { Program } from "@anchor-lang/core";

IDL types that were previously imported from @coral-xyz/anchor/dist/cjs/idl can now be imported directly from @anchor-lang/core:

- import { Idl } from "@coral-xyz/anchor/dist/cjs/idl";
+ import { Idl } from "@anchor-lang/core";

Solana 3.0

Anchor 1.0.0 targets Solana 3.x. If you are still on Solana 2.x you must upgrade your toolchain.

Solana CLI dependency removed

The anchor CLI no longer depends on the external solana CLI binary. Native implementations are now provided for the most common sub-commands: balance, airdrop, address, deploy, and others. This means the solana binary no longer needs to be on your PATH for Anchor commands to work.

anchor test / anchor localnet now use Surfpool by default

Surfpool replaces the local validator as the default backend for anchor test and anchor localnet. If you want to keep using the solana-test-validator, pass --validator legacy.

Duplicate mutable accounts disallowed by default

Passing the same mutable account twice in an instruction now produces a runtime error by default. If you intentionally need duplicate mutable accounts, opt in with the dup constraint:

#[derive(Accounts)]
pub struct MyIx<'info> {
    #[account(mut)]
    pub account_a: Account<'info, MyData>,
    #[account(mut, dup)]
    pub account_b: Account<'info, MyData>,
}

Legacy IDL instructions replaced by Program Metadata

The on-chain IDL management instructions that Anchor has used since the beginning have been removed and replaced with the new Program Metadata Program (PMP). IDL uploads through anchor deploy and anchor idl commands work as before; only the underlying mechanism has changed.

The program-id argument of anchor idl init and anchor idl upgrade is now optional — when omitted, the program ID is read from the address field of the IDL file itself.

If you are migrating an existing deployed program with IDL, you will need to close existing IDL accounts before deploying the new program based on anchor v1.0.0 as this will remove the IDL management instructions. This also depends on the previous v0.32.1 anchor cli.

Remove program account info from CPI context

The program field in CpiContext previously held a redundant copy of the program AccountInfo. It has been removed:

- CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts)
+ CpiContext::new(Token::id(), cpi_accounts)

interface-instructions feature removed

The interface-instructions feature flag and the #[interface] attribute have been removed. Use #[instruction(discriminator = <EXPR>)]! to specify custom discriminators.

Anchor.toml cleanup

  • The [registry] section is no longer recognized and should be removed.
  • The program arch build options have been removed from the CLI.

#[error_code] may only appear once per program

Having multiple #[error_code] blocks in a single program is now a compile-time error.

Client tx signing error no longer panics

RequestBuilder::send (and friends) previously panicked when signing failed. It now returns an Err instead.


AVM

avm self-update

Once your installed avm is v1-capable, you can update it without going through cargo install:

avm self-update

To bootstrap to a version that supports this command, install via cargo:

cargo install avm --git https://github.com/solana-foundation/anchor --tag v1.0.0 --locked

Additionally, avm will passively warn you when it detects that a newer version of itself is available.

Pre-release support

All avm commands (install, list, update) now understand pre-release version labels:

avm install latest-pre-release
avm list --pre-release
avm update --pre-release

CLI

Lifecycle hooks

You can now run shell commands at key points in the build/test/deploy lifecycle by adding a [hooks] section to your Anchor.toml:

[hooks]
pre_build  = "echo building..."
post_build = ["echo done", "echo done again"]
pre_test   = "some-setup-script"
post_deploy = "some-notify-script"

Supported hooks: pre_build, post_build, pre_test, post_test, pre_deploy, post_deploy.

LiteSVM test template is now the default

anchor init now generates a LiteSVM test template by default, replacing the previous TypeScript based default. You can still pick a different template explicitly:

anchor init my-program --test-template mollusk
anchor init my-program --test-template mocha

Program ID mismatch check

anchor build now checks that the program ID declared in your source code matches the public key in the program's keypair file and emits an error if they differ. This check is skipped during anchor test where ephemeral keypairs are common. You can skip this check during builds with anchor build --ignore-keys.

--install-agent-skills

Pass --install-agent-skills to anchor init to automatically install Solana agent AI skills into the new workspace.

login command removed

anchor login has been removed along with the [registry] section of Anchor.toml.


Lang

Migration<'info, From, To> account type

The new Migration type makes it straightforward to migrate accounts between two different data layouts in a single instruction:

#[derive(Accounts)]
pub struct MigrateMyAccount<'info> {
    #[account(mut)]
    pub my_account: Migration<'info, OldAccount, NewAccount>,
}

The account is deserialized as From, and serialized back as To on exit.

declare_program! improvements

Several renames apply to the code generated by declare_program!:

utils module renamed to parsers, and the parse methods renamed from try_from_bytes to parse:

- my_program::utils::Account::try_from_bytes(&data)?;
+ my_program::parsers::Account::parse(&data)?;
 
- my_program::utils::Event::try_from_bytes(&data)?;
+ my_program::parsers::Event::parse(&data)?;

errors module renamed to error. ProgramError renamed to <ProgramName>Error, where <ProgramName> is the PascalCase name of the declared program:

- my_program::errors::ProgramError
+ my_program::error::MyProgramError

declare_program! also now generates a typed instruction parser alongside the CPI helpers. Use my_program::parsers::Instruction::parse with a solana_instruction::Instruction to decode any instruction belonging to the program.

Composite (non-instruction) account structs used multiple times within a program previously caused duplicate definitions or incorrect instruction name derivation in the generated code. Both issues are now fixed: each composite account definition is guaranteed to be unique, and instruction names that would collide have a number appended until a unique name is found.

Error generation has also been improved: declare_program! previously interfered with the IDL error module generation of the declaring program. Programs that use declare_program! alongside their own #[error_code] block now produce correct error code definitions.

Use declare_program! with only anchor_client

It is no longer necessary to pull in anchor_lang just to use declare_program! in a client-side context. Adding anchor_client as a dependency is sufficient.

Remove lifetime definitions from Context

Three redundant lifetime parameters have been removed from Context. Most programs will not be affected; if you referenced these lifetimes explicitly you will need to update the annotations.

// Before (v0.32)
pub fn my_handler<'a, 'b, 'c, 'info>(
    ctx: Context<'a, 'b, 'c, 'info, MyAccounts<'info>>,
) -> Result<()> { ... }
 
// After (v1)
pub fn my_handler<'info>(ctx: Context<'info, MyAccounts<'info>>) -> Result<()> { ... }
// or simply (when the lifetime is inferred)
pub fn my_handler(ctx: Context<MyAccounts>) -> Result<()> { ... }

Deprecate AccountInfo in Accounts macro

Using AccountInfo directly inside an #[derive(Accounts)] struct now emits a compile-time warning. Prefer UncheckedAccount or a more specific account type.

Relaxed PDA seed syntax

The seed expressions accepted inside seeds = [...] constraints are now more flexible and support a broader set of Rust expressions. Note that more complex seed expressions reduce the likelihood of seeds being representable in the IDL and of successful automatic account resolution on the client side.

Owner check on account reload

Calling .reload() on an Account now re-validates the owner, the same as the initial load.

Generic Program type

Program<'info> can now be used without a type parameter for executable-only validation when the concrete program type is not known statically:

pub program: Program<'info>,

Owners exported from prelude

anchor_lang::Owners is now re-exported from the prelude, so you no longer need a separate use statement for it.

Borsh upgraded to 1.5.7

Both the Rust and TypeScript Borsh implementations have been updated to 1.5.7. Make sure your borsh dependency in Cargo.toml is compatible.

#[instruction(..)] argument validation

The compiler now enforces that the types and count of arguments in #[instruction(..)] match the corresponding instruction handler signature, catching mismatches that were previously silent.


IDL

Unsupported field types produce a hard error

Previously, defined types containing unsupported fields (e.g. tuple types) were silently omitted from the generated IDL. They now produce a compile-time error:

error: Unsupported type
  --> programs/name/src/lib.rs:37:8
   |
37 |     x: (u32, u32),
   |        ^^^^^^^^^^

If you were relying on silent omission, you will need to refactor those fields into supported types before building.

Full path account names supported in IDL generation

The IDL builder previously rejected account types that shared a short name with another type in a different module (e.g. program::module::Account conflicting with other::Account). The conflicting account names check has been removed, allowing full path account names to be used without errors.

address constraint resolves constants with numbers in their names

The address constraint previously failed to resolve constants whose identifiers contained numbers (e.g. MY_PROGRAM_V2_ID). This is now fixed.

serde_json is now optional

The serde_json dependency of anchor-lang-idl is now behind an opt-in feature flag, reducing compile times when JSON serialization is not needed.

External accounts excluded from IDL

Accounts defined in external programs (e.g. SPL token accounts referenced in your IDL) are no longer included in the generated IDL's accounts array, keeping the IDL focused on your own program's types.

Custom error offset respected

The offset = N argument in #[error_code] is now correctly reflected in the generated IDL, so the error codes in the IDL match what is emitted at runtime.


TypeScript

IDL fetching updated for PMP

The TypeScript client now fetches IDLs from the new Program Metadata Program storage. Existing code using Program.fetchIdl continues to work without changes.


Rust Client

FnMut closures for event subscriptions

program.on::<Event>(|event, slot| { ... }) now accepts FnMut closures, allowing you to capture mutable state from the surrounding scope.

Reduced re-exports from anchor-client

anchor-client previously re-exported the entirety of solana-sdk, which made it easy to discover types but pulled in a large dependency. It now only re-exports the types that are directly part of its public API. If you were relying on transitive solana-sdk types through anchor-client, you will need to add the relevant crates (solana-account, solana-pubkey, etc.) as explicit dependencies.


See the full list of notable changes in the CHANGELOG.

On this page

Edit on GitHub