Instruction Structure

Summary

An instruction has 3 fields: program_id (which program to invoke), accounts (AccountMeta list with is_signer/is_writable flags), and data (byte array of data that the program interprets).

Instruction structure

An Instruction consists of three fields:

  • program_id: The ID of the program being invoked.
  • accounts: An array of account metadata
  • data: A byte array with additional data to be used by the instruction.
Instruction struct
pub struct Instruction {
/// Pubkey of the program that executes this instruction.
pub program_id: Pubkey,
/// Metadata describing accounts that should be passed to the program.
pub accounts: Vec<AccountMeta>,
/// Opaque data passed to the program for its own interpretation.
pub data: Vec<u8>,
}

Program ID

The instruction's program_id is the public key address of the program that contains the instruction's execution logic. The runtime uses this field to route the instruction to the correct program for processing.

Account metadata

The instruction's accounts array is an ordered list of AccountMeta structs. Metadata must be provided for each account the instruction interacts with. The validator uses this metadata to determine which transactions can run in parallel. Transactions that write to different accounts can execute in parallel.

The diagram below depicts a transaction that contains a single instruction. The instruction's accounts array contains metadata for two accounts.

A transaction with one instruction. The instruction contains two AccountMeta structs in its accounts array.A transaction with one instruction. The instruction contains two AccountMeta structs in its accounts array.

Each AccountMeta has three fields:

  • pubkey: The account's public key address
  • is_signer: Set to true if the account must sign the transaction
  • is_writable: Set to true if the instruction modifies the account's data

To know which accounts an instruction requires, including which must be writable, read-only, or sign the transaction, you must refer to the implementation of the instruction, as defined by the program.

AccountMeta
pub struct AccountMeta {
/// An account's public key.
pub pubkey: Pubkey,
/// True if an `Instruction` requires a `Transaction` signature matching `pubkey`.
pub is_signer: bool,
/// True if the account data or metadata may be mutated during program execution.
pub is_writable: bool,
}

Data

The instruction's data field is a byte array that tells the program which function to invoke and supplies the arguments for that function. The data typically begins with a discriminator or index byte(s) that identifies the target function, followed by the serialized arguments. The encoding format is defined by each program (for example, Borsh serialization or a custom layout).

Common encoding conventions:

  • Core programs (System, Stake, Vote): Use a Bincode-serialized enum variant index followed by serialized arguments.
  • Anchor programs: Use an 8-byte discriminator (the first 8 bytes of the SHA-256 hash of "global:<function_name>") followed by Borsh-serialized arguments.

The runtime does not interpret the data field. It is passed as-is to the program's process_instruction entrypoint.

Compiled instruction

When instructions are serialized into a transaction message, they become CompiledInstruction structs that replace all public keys with compact integer indices into the message's account_keys array.

Example: SOL transfer instruction

The example below shows the structure of a SOL transfer instruction.

import { generateKeyPairSigner, lamports } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
// Generate sender and recipient keypairs
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
// Define the amount to transfer
const LAMPORTS_PER_SOL = 1_000_000_000n;
const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL
// Create a transfer instruction for transferring SOL from sender to recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount
});
console.log(JSON.stringify(transferInstruction, null, 2));
Console
Click to execute the code.

The code below shows the output from the previous code snippets. The format will differ between SDKs, but notice that each instruction contains the same three pieces of required information: program_id, accounts, data.

{
"accounts": [
{
"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC",
"role": 3,
"signer": {
"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC",
"keyPair": {
"privateKey": {},
"publicKey": {}
}
}
},
{
"address": "2mBY6CTgeyJNJDzo6d2Umipw2aGUquUA7hLdFttNEj7p",
"role": 1
}
],
"programAddress": "11111111111111111111111111111111",
"data": {
"0": 2,
"1": 0,
"2": 0,
"3": 0,
"4": 128,
"5": 150,
"6": 152,
"7": 0,
"8": 0,
"9": 0,
"10": 0,
"11": 0
}
}

The examples below show how to manually build the transfer instruction. (The Expanded Instruction tab is functionally equivalent to the Instruction tab.)

In practice, you usually don’t have to construct an Instruction manually. Most programs provide client libraries with helper functions that create the instructions for you. If a library isn't available, you can manually build the instruction.

const transferAmount = 0.01; // 0.01 SOL
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount * LAMPORTS_PER_SOL
});

Is this page helpful?

सामग्री तालिका

पृष्ठ संपादित करें

द्वारा प्रबंधित

© 2026 सोलाना फाउंडेशन। सर्वाधिकार सुरक्षित।
जुड़े रहें