Solana Foundations In Depth
Solana development stops feeling like a list of unrelated APIs once you see accounts, programs, transactions, currency, keys, clusters, and confirmation as one closed system.
Every other page in this section - basics, units, keypairs, clusters, transaction flow, and the EVM contrast - is a zoom into one face of that system, not a separate technology.
This page is the umbrella: how those pieces fit together so you can reason about a wallet transfer, a program deploy, or a failed RPC call with the same underlying picture.
Summary
- Solana is an accounts machine - programs execute against accounts named in atomic transactions, priced and stored in integer lamports, authorized by Ed25519 signatures (or PDAs), on a specific cluster, until a chosen commitment level says the result is durable enough for your UX.
- Insight: Fragmented mental models produce classic bugs - treating programs like contracts-with-storage, floating-point SOL amounts, wrong-cluster RPCs, or UI that treats
processedas final - that vanish once the pieces share one model. - Key Concepts: account, program, instruction, transaction, account meta, Sealevel, lamport, keypair, PDA, cluster, commitment, rent exemption.
- When to Use: First orientation before writing clients or programs; onboarding EVM or Web2 engineers; debugging "account not found," dropped transactions, or unexpected parallel contention.
- Limitations/Trade-offs: Explicit account lists and fixed account sizes buy parallelism and predictable storage costs, but force more design work than implicit storage models and make "one big global mapping" a non-starter.
- Related Topics: Solana Basics, SOL and lamports, keypairs and PDAs, clusters, transaction flow, and the Solana-vs-EVM mental model.
Foundations
The root abstraction is the account.
Every on-chain entity is one: a wallet balance, a deployed program's bytecode, a token mint, a user's profile struct, or a system-owned temporary holding all share the same structural fields - lamports, a data byte buffer, an owner program id, an executable flag, and a legacy rent epoch.
Nothing "else" lives on-chain outside that shape.
A program is an account whose executable flag is true and whose data holds BPF/SBF bytecode the runtime can load.
Programs are stateless in the application sense: they do not keep user balances or mappings inside their own account after deployment the way many EVM contracts keep storage slots.
Mutable application state lives in separate accounts owned by that program (or by the System Program until ownership is assigned).
Only the owner program may write an account's data; lamport transfers and a few system-level rules are the main exceptions you design around.
That separation is why you design account layouts instead of "contract storage," and why The Solana Mental Model vs. EVM exists as a focused contrast later in this section.
Native currency is SOL, but every on-chain amount is an integer number of lamports, where 1 SOL = 1_000_000_000 lamports.
Clients and programs treat balances, fees, and rent deposits as u64 / bigint integers - never as floating-point SOL at the protocol boundary.
Identity is Ed25519: a keypair is a 32-byte public key (the address) plus a secret key used to sign.
Program Derived Addresses (PDAs) are valid 32-byte addresses that intentionally sit off the Ed25519 curve so no private key exists; programs "sign" for them with seeds via invoke_signed, which is how program-owned vaults and deterministic per-user accounts work.
A cluster (mainnet-beta, devnet, testnet, or your localnet) is a fully separate chain with its own genesis, validators, and account set.
An address that holds SOL on devnet does not hold that balance on mainnet-beta; RPC URL, wallet network, and explorer must agree.
Commitment - processed, confirmed, finalized - is how far a transaction has progressed through leader execution and validator voting before your client treats it as good enough.
None of these topics is optional background; they are the same machine viewed at different scales.
Mechanics & Interactions
Work enters the network as a transaction: an atomic bundle of one or more instructions, each naming a program id and the accounts that instruction may touch.
Each account entry carries account metas - whether the account is writable and whether it must sign - so the runtime can lock accounts and enforce authorization before bytecode runs.
If any instruction fails, the whole transaction fails; partial success is not a Solana transaction outcome.
Sealevel, the parallel runtime on Agave 4.1.1 validators, uses those declared account lists to schedule non-overlapping transactions concurrently and to serialize transactions that share a writable account.
You buy throughput by partitioning state across accounts so unrelated users do not contend on one hot account.
A durable data account must hold at least the rent-exempt minimum lamports for its data size (queried via getMinimumBalanceForRentExemption); underfunded accounts are not a sustainable design for long-lived state.
Fees are paid in lamports by a designated fee payer; priority is expressed with compute unit limits and price, layered on top of signature-based base fees.
The path from client to confirmation is one pipeline, not separate "send" and "wait" products:
Client (wallet / kit / CLI)
| build instructions + account metas
| sign with Ed25519 keypair(s)
v
RPC node ---- sendTransaction ---->
|
| Gulf Stream forwards to upcoming leader
v
Leader (current slot)
| order via PoH, execute via Sealevel
| each instruction: load accounts -> run program -> write
v
Block propagation (Turbine) + validator votes
|
| commitment ladder:
| processed -> confirmed -> finalized
v
Client polls or subscribes until chosen commitment
Reading that flow with the foundations in mind: the client is assembling which accounts a stateless program may touch, funding any new accounts with lamports, signing with keypairs, targeting one cluster's RPC, and waiting for a commitment that matches the risk of the UX.
How a Transaction Flows deepens each hop; this page only needs you to see that hops are not a second architecture.
Cross-program work still sits inside one transaction: a program may CPI into another program, but every account the callee needs must already appear in the transaction's account list with correct metas.
Composability is explicit wiring, not ambient call context.
Advanced Considerations & Applications
Once the core loop is clear, design choices follow from it rather than from framework folklore.
Partition state so Sealevel can run independent users in parallel; a single global account that every user must write becomes a throughput ceiling and a rent/size problem.
Prefer PDAs for program-controlled vaults and deterministic "one account per user/entity" layouts; prefer ordinary keypairs for human authorities and fee payers.
Match commitment to consequence: dashboards often use confirmed; irreversible off-chain side effects and high-value settlements usually wait for finalized.
Keep environments strict: a dev keypair, a mainnet keypair, and a local validator keypair are different identities on different chains, even when base58 strings look similar across clusters only by coincidence of generation, not by shared state.
When porting from EVM, do not look for "storage inside the program"; look for "which accounts does this instruction declare, who owns them, and who signs?"
The table below compresses the two account models without replacing the dedicated EVM page.
| Aspect | EVM-style contracts | Solana accounts model |
|---|---|---|
| Where code lives | Contract bytecode at an address | Executable program account (program id) |
| Where state lives | Storage slots inside the contract | Separate data accounts owned by a program |
| How callers are identified | Implicit msg.sender | Explicit signer accounts in the instruction |
| How mappings work | mapping in contract storage | Many accounts, often PDAs seeded by key material |
| Parallelism | Limited by shared contract storage | Sealevel parallelizes non-overlapping account locks |
| Storage economics | Gas for SSTORE-style updates | Rent-exempt lamport deposit sized to account bytes |
| Atomic multi-step work | One transaction, sequential calls | One transaction, explicit multi-instruction + CPI |
Commitment levels are another operational table you should internalize early.
| Commitment | Rough meaning | Typical use |
|---|---|---|
processed | Leader executed; not yet heavily voted | Optimistic UI, speculative reads |
confirmed | Supermajority has voted on the block | Default for many app actions |
finalized | Rooted / practically irreversible under normal conditions | Settlements, withdrawals, cross-system callbacks |
Clusters form a third axis of the same model: localnet for fast CI, devnet for public sandbox SOL and shared testing, testnet for validator-facing experiments, mainnet-beta for real value.
Clusters & Networks and SOL, Lamports & Units flesh out operations and precision; here the advanced point is simply that amount math, key management, and confirmation policy only make sense after you fix which chain you are on.
Common Misconceptions
- "Programs store my app state like a smart contract." Programs are executables; state lives in accounts they own and that every instruction must pass in explicitly.
- "SOL amounts can be floats in the client if I am careful." On-chain values are integer lamports; convert at the UI boundary with integer/
bigintmath, not IEEE floats, for anything that will be signed or stored. - "PDAs are just fancy public keys with secret keys you derive." PDAs have no private key; only a program that knows the seeds can authorize PDA signatures through the runtime.
- "Devnet and mainnet-beta share accounts if the address matches." Clusters are separate ledgers; the same keypair controls different account states on each chain, and RPC must point at the cluster you mean.
- "If
sendTransactionreturns a signature, the transfer is final." A signature means the node accepted the submission path; durability depends on the commitment level you wait for afterward. - "Listing fewer accounts makes transactions cheaper or simpler." Omitting a required account fails at runtime; over-locking writable accounts reduces parallelism - correctness needs the true set, performance needs a well-partitioned design.
FAQs
What is the single sentence version of the Solana developer mental model?
Everything is an account; programs execute against accounts named in atomic transactions, funded in lamports, authorized by signatures or PDAs, on one cluster, until your chosen commitment says you can trust the result.
Why is "everything is an account" useful instead of cute slogans?
It unifies wallets, programs, mints, and data under one load/store and ownership model, so fees, rent, locks, and RPC reads all use the same vocabulary.
If programs are accounts, how is a program different from a data account?
A program account is marked executable and holds bytecode the loader runs; a data account holds application bytes interpreted by its owner program and is not executed as code.
Who is allowed to change an account's data bytes?
Only the program that owns the account may modify its data (subject to runtime rules); other programs need CPI into the owner or must hold lamports/signers for operations the system allows.
What does a transaction actually guarantee?
All of its instructions succeed or none of their effects commit; there is no partial application of a failed transaction's instruction list.
Why must every account be listed up front?
The runtime uses the list for locking, signature checks, and Sealevel scheduling; undeclared accounts cannot be loaded mid-flight the way some VMs allow implicit storage access.
How does Sealevel decide what can run in parallel?
Transactions that do not share conflicting account locks - especially overlapping writable accounts - can execute concurrently; conflicting ones are ordered so writes stay consistent.
What is a lamport and why not use SOL everywhere?
A lamport is the base integer unit (1 SOL = 1e9 lamports); the chain and APIs speak integers so amounts never depend on floating-point rounding.
What is rent exemption in one line?
A data-size-based minimum lamport balance that keeps an account alive without ongoing rent collection under current economics - fund it at creation via the rent-exempt minimum.
How do keypairs and PDAs both fit the same identity story?
Keypairs prove human or server authority with Ed25519 signatures; PDAs are program-controlled addresses without secrets, authorized only when the owning program supplies the correct seeds at CPI time.
Why does my explorer show nothing when my CLI balance looks fine?
Almost always a cluster mismatch - CLI on devnet, explorer on mainnet-beta, or an RPC URL pointing at a different network than the wallet.
Which commitment should my dapp wait for by default?
Many product actions use confirmed for responsive UX; use finalized before irreversible external effects, and treat processed as optimistic only.
How is this page different from "The Solana Mental Model vs. EVM"?
This page is the full builder model (accounts through confirmation); the EVM page is a focused porting contrast for engineers who already think in contracts-with-storage.
Do Anchor or @solana/kit change this mental model?
No - Anchor 0.32.1 and @solana/kit 7.0.0 are ergonomic layers over the same accounts, instructions, metas, and RPC/commitment surfaces described here.
Where should I go next after this page?
Skim Solana Basics for concrete examples, then deepen currency, keys, clusters, and transaction flow via the Related links below as you build.
Related
- Solana Basics - hands-on orientation to accounts, programs, transactions, and SOL
- SOL, Lamports & Units - integer denominations, precision, and fee/rent amounts
- Keypairs & Addresses - Ed25519 identity, signing roles, and PDA addresses
- The Solana Mental Model vs. EVM - accounts-and-programs versus contracts-with-storage
- How a Transaction Flows - client to leader to commitment in operational detail
- Clusters & Networks - mainnet-beta, devnet, testnet, and localnet as separate chains
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, Rust 1.91.1, and @solana/kit 7.0.0.