Skip to main content
Anchor provides a TypeScript client library (@anchor-lang/core) that simplifies the process of interacting with Solana programs from JavaScript or TypeScript applications.
The @anchor-lang/core library is only compatible with the legacy version (v1) of @solana/web3.js and @solana/spl-token. It is not compatible with the new version (v2) of @solana/web3.js.

Installation

Install the Anchor client library along with Solana web3.js:
npm install @anchor-lang/core @solana/web3.js

Core Concepts

The Anchor TypeScript client is built around three main concepts:

Program

The main interface for interacting with on-chain programs

Provider

Combines connection and wallet for signing and sending transactions

Workspace

Auto-discovers programs in Anchor projects (Node.js only)

Creating a Program Instance

To interact with an Anchor program, you need to create a Program instance using the program’s IDL file.

Constructor Signature

new Program<IDL>(
  idl: IDL,
  provider?: Provider,
  coder?: Coder
)

Frontend/React Example

When integrating with a frontend using the Solana wallet adapter:
import { Program, AnchorProvider } from "@anchor-lang/core";
import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react";
import type { MyProgram } from "./idl-type";
import idl from "./idl.json";

const { connection } = useConnection();
const wallet = useAnchorWallet();

// Create provider
const provider = new AnchorProvider(connection, wallet, {
  preflightCommitment: "processed"
});

// Create program instance
const program = new Program<MyProgram>(idl, provider);

Without Wallet

You can create a Program instance without a wallet for read-only operations:
import { Connection, clusterApiUrl } from "@solana/web3.js";
import { Program } from "@anchor-lang/core";
import type { MyProgram } from "./idl-type";
import idl from "./idl.json";

const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

const program = new Program<MyProgram>(idl, { connection });

Fetch IDL from Chain

If an IDL has been deployed to the blockchain using anchor idl init:
import { Program } from "@anchor-lang/core";
import { Connection, PublicKey } from "@solana/web3.js";

const connection = new Connection("https://api.devnet.solana.com");
const programId = new PublicKey("Your1Program2Address3Here");

// Fetch IDL from chain
const program = await Program.at(programId, { connection });

AnchorProvider

The AnchorProvider combines a Solana connection and wallet to handle transaction signing and sending.

API

class AnchorProvider {
  constructor(
    readonly connection: Connection,
    readonly wallet: Wallet,
    readonly opts: ConfirmOptions
  )

  // Create provider from local filesystem keypair (Node.js only)
  static local(url?: string, opts?: ConfirmOptions): AnchorProvider

  // Create provider from ANCHOR_PROVIDER_URL env variable (Node.js only)
  static env(): AnchorProvider

  // Send and confirm transaction
  sendAndConfirm(
    tx: Transaction | VersionedTransaction,
    signers?: Signer[],
    opts?: ConfirmOptions
  ): Promise<TransactionSignature>

  // Send multiple transactions
  sendAll(
    txWithSigners: { tx: Transaction; signers?: Signer[] }[],
    opts?: ConfirmOptions
  ): Promise<TransactionSignature[]>

  // Simulate transaction
  simulate(
    tx: Transaction | VersionedTransaction,
    signers?: Signer[],
    commitment?: Commitment
  ): Promise<SimulatedTransactionResponse>
}

Example: Node.js Provider

import { AnchorProvider } from "@anchor-lang/core";
import { Connection } from "@solana/web3.js";

// Use local keypair (reads from ~/.config/solana/id.json)
const provider = AnchorProvider.local();

// Or specify custom URL
const provider = AnchorProvider.local("https://api.devnet.solana.com");

// Or use environment variable
const provider = AnchorProvider.env();

Workspace (Node.js Only)

In Anchor projects, you can use the workspace object to automatically discover and load programs:
import * as anchor from "@anchor-lang/core";
import { Program } from "@anchor-lang/core";
import { MyProgram } from "../target/types/my_program";

// Configure provider
anchor.setProvider(anchor.AnchorProvider.env());

// Access program from workspace
const program = anchor.workspace.MyProgram as Program<MyProgram>;

// Now you can call program methods
const tx = await program.methods.initialize().rpc();
The workspace automatically:
  • Reads IDL files from target/idl/
  • Parses Anchor.toml for program configuration
  • Creates typed Program instances

Invoking Instructions

The program.methods namespace provides a builder API for creating and sending transactions.

Builder Pattern

1

Start with .methods

Call the instruction name with its arguments
program.methods.initialize(arg1, arg2)
2

Provide accounts with .accounts()

Pass required accounts (PDAs and common accounts are often auto-resolved)
.accounts({ account1: publicKey1, account2: publicKey2 })
3

Add signers with .signers() (optional)

Include additional signers beyond the wallet
.signers([keypair1, keypair2])
4

Execute

Choose how to execute: .rpc(), .transaction(), or .instruction()

Execution Methods

Builds, signs, and sends the transaction in one call. Returns the transaction signature.
const signature = await program.methods
  .initialize(new BN(42))
  .accounts({
    counter: counterKeypair.publicKey,
    user: wallet.publicKey,
    systemProgram: SystemProgram.programId,
  })
  .signers([counterKeypair])
  .rpc();

console.log("Transaction signature:", signature);
Best for: Simple, single-instruction transactions

Additional Options

The methods builder supports additional configuration:
await program.methods
  .initialize()
  .accounts({ /* ... */ })
  .signers([keypair])
  .preInstructions([/* instructions to run before */])
  .postInstructions([/* instructions to run after */])
  .remainingAccounts([/* additional AccountMeta[] */])
  .rpc({
    skipPreflight: false,
    commitment: "confirmed",
    maxRetries: 3,
  });

Fetching Accounts

The program.account namespace provides methods to fetch and deserialize program accounts.

Fetch Single Account

const counterAccount = await program.account.counter.fetch(counterAddress);
console.log("Count:", counterAccount.count.toString());

Fetch Multiple Accounts

const accounts = await program.account.counter.fetchMultiple([
  address1,
  address2,
  address3,
]);

accounts.forEach((account, index) => {
  if (account) {
    console.log(`Account ${index}:`, account.count.toString());
  }
});

Fetch All Accounts

const allCounters = await program.account.counter.all();

allCounters.forEach(({ publicKey, account }) => {
  console.log(`${publicKey.toString()}: ${account.count.toString()}`);
});

Fetch with Filters

Use memcmp (memory compare) to filter accounts. Remember: the first 8 bytes are the account discriminator.
// Filter accounts where a u64 field at offset 8 equals a specific value
const value = new BN(42);
const valueBuffer = value.toArrayLike(Buffer, "le", 8);

const filteredAccounts = await program.account.counter.all([
  {
    memcmp: {
      offset: 8, // Skip 8-byte discriminator
      bytes: bs58.encode(valueBuffer),
    },
  },
]);

Event Listeners

Subscribe to program events emitted via logs:
// Subscribe to events
const listenerId = program.addEventListener(
  "CounterUpdated",
  (event, slot, signature) => {
    console.log("Event:", event);
    console.log("Slot:", slot);
    console.log("Signature:", signature);
  }
);

// Unsubscribe when done
await program.removeEventListener(listenerId);

Program Properties

The Program instance exposes useful properties:
// Program ID
const programId: PublicKey = program.programId;

// IDL (camelCased)
const idl = program.idl;

// Raw IDL (original format)
const rawIdl = program.rawIdl;

// Provider
const provider = program.provider;

// Coder for encoding/decoding
const coder = program.coder;

Complete Example

Here’s a complete example demonstrating common operations:
example.ts
import {
  Connection,
  Keypair,
  LAMPORTS_PER_SOL,
  SystemProgram,
} from "@solana/web3.js";
import { Program, AnchorProvider, BN } from "@anchor-lang/core";
import type { Counter } from "./idl-type";
import idl from "./idl.json";

async function main() {
  // Setup
  const connection = new Connection("http://127.0.0.1:8899", "confirmed");
  const payer = Keypair.generate();
  const counter = Keypair.generate();

  // Airdrop SOL
  const signature = await connection.requestAirdrop(
    payer.publicKey,
    LAMPORTS_PER_SOL
  );
  await connection.confirmTransaction(signature);

  // Create program instance
  const wallet = {
    publicKey: payer.publicKey,
    signTransaction: async (tx) => {
      tx.partialSign(payer);
      return tx;
    },
    signAllTransactions: async (txs) => {
      return txs.map((tx) => {
        tx.partialSign(payer);
        return tx;
      });
    },
  };

  const provider = new AnchorProvider(connection, wallet, {});
  const program = new Program<Counter>(idl, provider);

  // Initialize counter
  const initTx = await program.methods
    .initialize()
    .accounts({
      counter: counter.publicKey,
      payer: payer.publicKey,
      systemProgram: SystemProgram.programId,
    })
    .signers([counter])
    .rpc();
  console.log("Initialize tx:", initTx);

  // Increment counter
  const incrementTx = await program.methods
    .increment()
    .accounts({
      counter: counter.publicKey,
    })
    .rpc();
  console.log("Increment tx:", incrementTx);

  // Fetch account
  const counterAccount = await program.account.counter.fetch(counter.publicKey);
  console.log("Counter value:", counterAccount.count.toString());
}

main();

TypeScript Type Safety

When you run anchor build, Anchor generates TypeScript types in target/types/:
import { Program } from "@anchor-lang/core";
import { MyProgram } from "../target/types/my_program";
import idl from "../target/idl/my_program.json";

const program = new Program<MyProgram>(idl, provider);

// TypeScript provides autocomplete and type checking
const tx = await program.methods
  .myInstruction(arg1, arg2) // Args are type-checked
  .accounts({
    // Account names are validated
    account1: publicKey1,
    account2: publicKey2,
  })
  .rpc();

// Account data is properly typed
const account = await program.account.myAccount.fetch(address);
console.log(account.field1); // TypeScript knows the account structure

API Reference

Program Class

Property/MethodDescription
program.methods.<instruction>()Builder for invoking instructions
program.account.<account>.fetch()Fetch and deserialize single account
program.account.<account>.all()Fetch all accounts of a type
program.addEventListener()Subscribe to program events
program.programIdThe program’s public key
program.providerThe provider instance
program.idlThe program’s IDL

MethodsBuilder Class

MethodDescription
.accounts(accounts)Specify instruction accounts
.signers(signers)Add additional signers
.remainingAccounts(accounts)Add remaining accounts
.preInstructions(ixs)Instructions to execute before
.postInstructions(ixs)Instructions to execute after
.rpc(opts?)Build, sign, and send transaction
.transaction()Build transaction without sending
.instruction()Build instruction only
.simulate()Simulate transaction

Next Steps

Rust Client

Learn about the Rust client library

Program IDL

Understand the IDL format

Build docs developers (and LLMs) love