Solana Basics
9 examples to get you started with Solana fundamentals - 6 basic and 3 intermediate. Covers accounts, programs, transactions, SOL, clusters, and the developer workflow on Agave 4.1.1.
Prerequisites
Install the Solana CLI 3.0.10 and create a default keypair on devnet.
sh -c "$(curl -sSfL https://release.anza.xyz/v3.0.10/install)"
solana --version
solana config set --url devnet
solana-keygen new --no-bip39-passphrase -o ~/.config/solana/id.json
solana airdrop 2For TypeScript client examples, use @solana/kit 7.0.0:
npm install @solana/kit@7.0.0Basic Examples
1. Read an Account Balance
Every address on Solana maps to an account - even if it holds zero lamports.
import { createSolanaRpc, address, lamports } from "@solana/kit";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const pubkey = address("11111111111111111111111111111111");
const { value } = await rpc.getBalance(pubkey).send();
console.log(`Balance: ${Number(lamports(value)) / 1e9} SOL`);- Balances are stored in lamports (u64), not SOL floats
getBalancereturns lamports directly from the account's lamport field- Uninitialized addresses return 0 - no account exists until funded
Related: SOL, Lamports & Units - precision and conversions
2. Understand the Account Model
Accounts are the single abstraction for all on-chain state.
// Conceptual layout - every account has these fields
pub struct Account {
pub lamports: u64, // SOL balance in lamports
pub data: Vec<u8>, // arbitrary byte buffer
pub owner: Pubkey, // program allowed to write data
pub executable: bool, // true for deployed programs
pub rent_epoch: u64, // rent tracking (legacy field)
}- Programs are accounts with
executable = trueand code indata - Data accounts hold program state - owned by the program that interprets them
- Only the owner program can mutate an account's data (with signer exceptions)
Related: The Solana Mental Model vs. EVM - accounts vs contracts
3. Send a Simple Transfer
A transaction with one System Program instruction moves SOL between accounts.
solana transfer <RECIPIENT_PUBKEY> 0.1 --allow-unfunded-recipient- The CLI builds a transaction with the System Program
Transferinstruction - The sender keypair signs as fee payer and as the source account authority
--allow-unfunded-recipientcreates the destination if it has no account yet
Related: How a Transaction Flows - client to confirmation
4. Inspect a Transaction
Use the CLI or RPC to see instructions, signers, and compute units consumed.
solana confirm -v <SIGNATURE>-vprints each instruction's program ID, accounts, and data- Logs show compute units (CU) consumed per instruction
- Failed transactions still appear on-chain with error codes in logs
Related: Keypairs & Addresses - who signs what
5. Choose the Right Cluster
Solana runs multiple independent clusters with different purposes.
solana config set --url devnet # free test SOL, public RPC
solana config set --url testnet # validator testing, less stable
solana config set --url mainnet-beta # production - real SOL
solana-test-validator # local Agave 4.1.1 node- Devnet is the default for application development
- Local validator gives full control and zero network latency
- Mainnet-beta requires real SOL and priority fees during congestion
Related: Clusters & Networks - when to use each
6. Understand Slots and Timing
Solana targets ~400 ms slots; leaders produce blocks per slot.
solana slot
solana block-time $(solana slot)- A slot is a time window where one validator is the block producer
- An epoch is a fixed number of slots (~432,000 slots, ~2 days)
- Skipped slots happen when the assigned leader is offline or slow
Related: Slots, Blocks & Epochs - epoch schedule details
Intermediate Examples
7. Build a Transaction with @solana/kit
Kit uses a functional pipe to assemble versioned transactions.
import {
createSolanaRpc,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
pipe,
address,
getSignatureFromTransaction,
signTransactionMessageWithSigners,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const feePayer = address("YOUR_FEE_PAYER_PUBKEY");
const recipient = address("RECIPIENT_PUBKEY");
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const transferIx = getTransferSolInstruction({
source: feePayer,
destination: recipient,
amount: 100_000_000n, // 0.1 SOL in lamports
});
const txMessage = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayer(feePayer, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(transferIx, m),
);
// Sign with your keypair signer, then send via sendTransaction- Kit separates message building from signing and sending
- Amounts are always
bigintlamports - never JavaScript floats - Version 0 transactions support address lookup tables for more accounts
Related: Wallets & Explorers - devnet workflow
8. Generate and Use a Keypair
Ed25519 keypairs are the root of identity and signing on Solana.
solana-keygen new --outfile ./dev-wallet.json --no-bip39-passphrase
solana-keygen pubkey ./dev-wallet.jsonimport { createKeyPairSignerFromBytes } from "@solana/kit";
import { readFileSync } from "node:fs";
const secret = JSON.parse(readFileSync("./dev-wallet.json", "utf8"));
const signer = await createKeyPairSignerFromBytes(Uint8Array.from(secret));
console.log(signer.address);- The JSON file is a 64-byte secret key array - treat it like a password
- Public keys (addresses) are 32-byte Ed25519 points, base58-encoded
- Never commit keypair files to version control
Related: Keypairs & Addresses - signing model
9. Trace a Transaction End-to-End
Follow a transfer from client submission to finalized confirmation.
# 1. Send
SIG=$(solana transfer <RECIPIENT> 0.01 --output json | jq -r .signature)
# 2. Poll confirmation
solana confirm $SIG --commitment confirmed
# 3. Inspect in explorer
echo "https://explorer.solana.com/tx/$SIG?cluster=devnet"- Processed - node has seen it; may still be dropped
- Confirmed - supermajority voted on the block containing it
- Finalized - block is rooted and cannot be rolled back
Related: How a Transaction Flows - full pipeline
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.