Account Types

Summary

Program accounts hold executable sBPF code. Data accounts store state, owned by programs. System accounts are owned by the System Program. Sysvars provide cluster-wide state accessible at predefined addresses.

The executable field determines an account's category:

This separation of code from mutable state means a program is deployed once and can manage any number of data accounts.

Program accounts

A program account stores executable code. Every program account is owned by a loader program. When a program is deployed, the runtime creates a program account to hold its bytecode.

Diagram of a program account, its 4 components and its loader program.Diagram of a program account, its 4 components and its loader program.

Program data accounts

Programs deployed using loader-v3 (see Loader programs) do not store executable bytecode in their own data field. Instead, their data points to a separate program data account that contains the program code. (See the diagram below.)

A program account with data. The data points to a separate program data accountA program account with data. The data points to a separate program data account

During program deployment or upgrades, buffer accounts are used to temporarily stage the upload.

The following example fetches the Token Program account. The executable field is true, confirming it is a program account.

import { Address, generateKeyPairSigner } from "@solana/kit";
import { createClient } from "@solana/kit-client-rpc";
const feePayer = await generateKeyPairSigner();
const client = createClient({
url: "https://api.mainnet.solana.com",
payer: feePayer
});
const programId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address;
const accountInfo = await client.rpc
.getAccountInfo(programId, { encoding: "base64" })
.send();
console.log(accountInfo);
Console
Click to execute the code.

Data accounts

Data accounts do not contain executable code. They store program-defined state.

Program state account

Programs store their state in data accounts. Creating a program state account involves two steps:

  1. Invoke the System Program to create the account. The System Program transfers ownership to the specified program.
  2. The owning program initializes the account's data field according to its instructions.

Diagram of a data account owned by a program accountDiagram of a data account owned by a program account

The following example creates and fetches a Token Mint account owned by the Token 2022 program.

import { generateKeyPairSigner } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
import { systemProgram } from "@solana-program/system";
import {
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS,
fetchMint
} from "@solana-program/token-2022";
const client = await createLocalClient().use(systemProgram());
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();
const transactionSignature = await client.sendTransaction([
client.system.instructions.createAccount({
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
}),
getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: client.payer.address
})
]);
console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", transactionSignature.context.signature);
const accountInfo = await client.rpc.getAccountInfo(mint.address).send();
console.log(accountInfo);
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log(mintAccount);
Console
Click to execute the code.

System accounts

Accounts that remain owned by the System Program after creation are called system accounts. Sending SOL to a new address for the first time creates a new account at that address owned by the System Program.

All wallet accounts are system accounts. The fee payer on a transaction must be a system account, because only System Program-owned accounts can pay transaction fees.

A wallet owned by the System Program containing 1,000,000 lamportsA wallet owned by the System Program containing 1,000,000 lamports

The following example generates a new keypair, funds it with SOL, and fetches the account. The owner field is 11111111111111111111111111111111 (the System Program).

import { generateKeyPairSigner, lamports } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
const client = await createLocalClient();
// Generate a new keypair
const keypair = await generateKeyPairSigner();
console.log(`Public Key: ${keypair.address}`);
// Funding an address with SOL automatically creates an account
const signature = await client.airdrop(
keypair.address,
lamports(1_000_000_000n)
);
const accountInfo = await client.rpc.getAccountInfo(keypair.address).send();
console.log(accountInfo);
Console
Click to execute the code.

Sysvar accounts

Sysvar accounts are special accounts at predefined addresses that provide read-only access to cluster state data. They update dynamically each slot.

SysvarAddressPurpose
ClockSysvarC1ock11111111111111111111111111111111Current slot, epoch, and Unix timestamp
EpochScheduleSysvarEpochSchedu1e111111111111111111111111Epoch scheduling constants set in genesis
EpochRewardsSysvarEpochRewards1111111111111111111111111Epoch rewards distribution status and progress
RentSysvarRent111111111111111111111111111111111Rental rate and exemption threshold
SlotHashesSysvarS1otHashes111111111111111111111111111Most recent hashes of the slot's parent banks
StakeHistorySysvarStakeHistory1111111111111111111111111Stake activations and deactivations per epoch
LastRestartSlotSysvarLastRestartS1ot1111111111111111111111Last cluster restart slot
InstructionsSysvar1nstructions1111111111111111111111111Serialized instructions of the current transaction
SlotHistorySysvarS1otHistory11111111111111111111111111Record of which slots were produced over the last epoch

The following example fetches and deserializes the Sysvar Clock account.

import { generateKeyPairSigner } from "@solana/kit";
import { createClient } from "@solana/kit-client-rpc";
import { fetchSysvarClock, SYSVAR_CLOCK_ADDRESS } from "@solana/sysvars";
const feePayer = await generateKeyPairSigner();
const client = createClient({
url: "https://api.mainnet.solana.com",
payer: feePayer
});
const accountInfo = await client.rpc
.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" })
.send();
console.log(accountInfo);
// Automatically fetch and deserialize the account data
const clock = await fetchSysvarClock(client.rpc);
console.log(clock);
Console
Click to execute the code.

Is this page helpful?

Table of Contents

Edit Page

Managed by

© 2026 Solana Foundation.
All rights reserved.
Get connected