Pinocchio In Depth
Solana program frameworks sit on the same runtime: SBF bytecode, explicit account metas, compute unit (CU) metering, and CPI. What changes is how much validation, codegen, and client glue the framework generates for you.
Anchor 0.32.1 optimizes for developer velocity and a full IDL pipeline. Pinocchio and Steel optimize for thinner abstractions, smaller binaries, and tighter control over hot-path cost.
This page is the section umbrella: why lightweight frameworks exist, how Pinocchio and Steel relate to Anchor and native solana-program, how to think about CU and binary size, how interop and migration actually work, and when each choice is justified.
Summary
- Lightweight frameworks (Pinocchio, Steel) are thinner native-style toolkits that cut macro and dependency overhead so you can validate accounts, dispatch instructions, and CPI with less generated code than Anchor, at the cost of more manual security and client schema work.
- Insight: Many products never need to leave Anchor; some hit CU ceilings, deploy size pressure, or audit preferences that reward explicit checks. Picking the wrong stack wastes months; picking the right one (or a hybrid CPI boundary) is an economic decision, not a purity contest.
- Key Concepts: Pinocchio, Steel, Anchor, native program, compute units (CU), binary size (
.so), IDL / Codama, entrypoint, manual validation, CPI interop, hot-path rewrite. - When to Use: Orienting a team on framework options; justifying a rewrite with metrics; designing Anchor periphery + Pinocchio core; deciding whether Steel's middle ground fits; planning migration without breaking account layouts or clients.
- Limitations/Trade-offs: You lose Anchor's constraint macros and default IDL story; security review surface grows; client codegen becomes an explicit pipeline; gains vanish if Token CPI or syscalls dominate the instruction budget.
- Related Topics: Lightweight overview, Pinocchio basics, building programs, Steel, CU and binary-size wins, interop and migration, and when to use which framework.
Foundations
A Solana program is still an executable account that implements roughly process_instruction(program_id, accounts, data). Frameworks differ in entrypoint wiring, AccountInfo surfaces, and how much validation and client glue they generate.
Why lightweight frameworks exist
Anchor's value is real: accounts structs, constraint attributes, errors, events, and IDL-driven clients on @solana/kit 7.0.0. That convenience costs dependency weight, macro-expanded checks, and patterns that can inflate CU and .so size on tight paths.
Lightweight frameworks answer a product question, not a purity contest: can we keep correctness while paying less per instruction and per deploy?
They show up when hot instructions hit the CU budget, binary size or deploy rent hurts, auditors prefer explicit checks, or a shared core multiplies every saved CU across volume. They do not exist because Anchor is wrong. Anchor 0.32.1 remains the default for most application programs.
Pinocchio vs Anchor (and vs raw native)
| Dimension | Anchor 0.32.1 | Pinocchio | Raw native | Steel |
|---|---|---|---|---|
| Ergonomics | Highest | Low-mid | Lowest | Mid |
| Deps / glue | Higher | Minimal | Minimal | Light |
| Validation | Declarative constraints | Manual | Manual | Helpers + conventions |
| IDL / clients | Built-in path | External (Codama / hand) | Manual | External |
| CU / size | Baseline higher | Often lower when measured | Lowest ceiling | Mid-low |
| Best fit | MVP, admin, standard apps | Hot cores | Max transparency | Multi-ix native + structure |
Pinocchio is a minimal Rust crate for native-style programs: entrypoint macro, account info, pubkeys, errors, and invoke helpers, usually with a small tree and #![no_std]-friendly posture. You still:
- Enter via
entrypoint!(process_instruction). - Parse instruction data (opcode, Borsh, or custom).
- Validate signers, writability, owners, PDAs, and layout yourself.
- Mutate accounts and CPI with
invoke/invoke_signed.
You do not get Anchor's #[derive(Accounts)] safety net. That is both the point and the risk.
Steel sits between Pinocchio and Anchor: more instruction/account structure than raw Pinocchio, less macro and IDL machinery than Anchor. Reach for it when Pinocchio feels too bare but Anchor's cost profile is wrong.
CU and binary size
CU meters instruction work. Binary size is the deployed .so footprint (and deploy economics). Lightweight stacks can cut framework glue, discourage heavy logging on hot paths, and encourage tight parsers. They cannot erase syscall floors, SPL Token / Token-2022 CPI baselines, or your algorithm.
"We rewrote in Pinocchio" is not a metric. Simulated unitsConsumed on a fixed transaction, plus release .so size, is a metric.
Interop, migration, and choice
Programs interoperate through CPI and shared account bytes, not shared frameworks. Anchor can call Pinocchio (and reverse) when metas, owners, discriminators, and PDA seeds agree. Migration usually freezes layouts and seeds, moves one hot path first, dual-runs or CPI-boundaries during cutover, updates Codama/IDL with clients, then tightens upgrade authority after metrics and review.
Default to Anchor until profiling, size, or audit constraints force otherwise. Prefer hybrid over big-bang rewrites. Pinocchio for minimal cores; Steel for structure without full Anchor; raw native when the team already owns full solana-program discipline.
Mechanics & Interactions
Framework choice shows up in entry/dispatch, validation, state and CPI, and clients.
Client (Kit / Codama / hand-built ix)
|
v
Transaction names accounts + program id
|
v
Runtime loads SBF program (.so)
|
v
Entrypoint -> parse ix -> validate accounts
|
+--> mutate program-owned data
+--> CPI to System / Token / others
|
v
CU consumed; success or ProgramError
Entrypoint and dispatch. Pinocchio looks like native: one entry, then match or enum unpack. Steel adds registry-style structure for multi-instruction programs. Anchor generates dispatch from the program module and accounts types. All three are still one SBF program id to the runtime.
Validation. Anchor encodes signer, mut, owner, seeds, and token checks as attributes. Pinocchio reimplements them in Rust, ideally via shared helpers. Skipping checks to "save CU" is almost never worth it: exploit cost dwarfs compute savings.
State and PDAs. Keep one source of truth for discriminators, field order, PDA seeds/bumps, and error codes. Across CPI or migration boundaries, bytes and seeds must match, not only conceptual field names.
CPI across stacks. Typical shapes: Anchor admin -> Pinocchio settlement core; Pinocchio -> System/Token; Steel app -> Anchor ecosystem program. Account order and writability must match the callee. Framework macros do not auto-align CPI lists across crates.
Clients and IDL. Anchor's strength is IDL into typed clients. Pinocchio and Steel need Codama (or hand-built codecs). @solana/kit 7.0.0 does not care which framework built the .so; it needs correct wire formats. Budget client work when you leave Anchor.
Measuring wins.
- Baseline CU p50/p99 on a fixed account graph (Surfpool / simulate).
- Rewrite only the hot instruction or extract a CPI core.
- Re-simulate identical inputs; compare release
.sosize. - Lock CU ceilings in LiteSVM/CI.
If Token CPI dominates, fix algorithm or account design before shopping frameworks.
Advanced Considerations & Applications
Hybrid architecture
Full rewrites are rare. A common production shape:
| Layer | Stack | Reason |
|---|---|---|
| Admin, config, ops | Anchor 0.32.1 | Velocity, IDL, familiar ix surface |
| Matching / settle / hot mint | Pinocchio or Steel | CU and size under load |
| Shared state | Stable layouts + versioned discriminators | Safe upgrades |
| Clients | Kit + Codama (Anchor IDL where still Anchor) | Typed builders |
Spend systems effort where CU is product-critical; keep Anchor where CU is cheap.
Security and size beyond the framework swap
Leaving Anchor increases review surface: every signer, owner, PDA, remaining-accounts bound, and error code is hand-owned. Invest in validation helpers, invariant tests, and parser fuzzing. Treat constraint removal as a security project, not only a performance project.
Size also comes from heavy on-chain crates, msg!/formatting on hot paths, duplicated serialization, and unused features. Pin release cargo build-sbf profiles and re-measure after Agave 4.1.1 / CLI bumps.
Steel, migration patterns, and a decision rubric
Steel is a process bet: conventions reduce bugs faster than pure minimalism without full Anchor cost. Use it when instruction count is high, several programs need shared patterns, and you still accept external IDL plus manual security. Profile Steel against both Anchor and Pinocchio on your hot ix.
| Pattern | Use when | Watch for |
|---|---|---|
| CPI extract (new program id) | Hot core isolatable | Dual deploy, authority |
| In-place upgrade rewrite | Same id, same layouts | Upgrade key, verifiable builds |
| Dual-run clients | Gradual cutover | Two schemas in flight |
| Stay Anchor, optimize inner | Mild CU pain | Logs, zero-copy, flags |
Never casually change layouts mid-migration without a versioned migration ix and client plan.
Score roughly 0-2 each: Anchor skill, CU headroom, binary pressure, built-in IDL need, audit timeline, systems-Rust depth.
- Low CU/size pressure + strong IDL need -> Anchor.
- High CU/size + strong Rust + willing Codama -> Pinocchio (or Steel if structure helps).
- Mixed surface -> hybrid CPI.
- Unsure -> Anchor until simulation proves pain.
Attach simulate numbers to a short ADR so the next rewrite debate starts from data.
Common Misconceptions
- "Pinocchio always uses fewer CU than Anchor." Often true on framework-heavy paths, never guaranteed. Syscalls and Token CPI can dominate; measure fixed txs.
- "Leaving Anchor means fewer security checks." You own every check Anchor used to generate. Lightweight is not lighter security.
- "We must rewrite the whole program." One hot instruction or CPI core often captures most gain with less risk.
- "Steel is unusable / Pinocchio is always production-ready." Both are stack choices. Pin crate versions to Agave 4.1.1 and your audit bar.
- "Clients will invent the wire format." Without IDL or Codama, TypeScript clients rot. Publish schemas with deploys.
- "Binary size is cosmetic." Larger
.sofiles affect deploy cost and ops friction. - "Framework choice replaces algorithm design." Bad account graphs and extra CPIs lose to any stack. Fix design when profiles say so.
FAQs
What is Pinocchio in one sentence?
A minimal Rust framework for native-style Solana programs that prioritizes a small dependency surface and low-overhead entry, account, and CPI helpers compared with Anchor.
Why do lightweight frameworks exist if Anchor is popular?
Some programs hit CU ceilings, deploy size limits, or audit preferences for explicit checks; thinner stacks trade convenience for control on those paths.
Is Anchor obsolete?
No. Anchor 0.32.1 remains the default velocity stack; lightweight frameworks are specialized tools, not a universal replacement.
How does Pinocchio differ from raw solana-program?
Same general model (entrypoint, accounts, manual validation) with a focused crate API aimed at lower overhead and a tighter dependency tree.
Where does Steel fit?
Between Pinocchio and Anchor: more structure than raw Pinocchio, less macro/IDL weight than Anchor. Profile it; do not assume free CU.
Will switching frameworks fix Token CPI cost?
Usually no. Token CPI and syscalls have inherent cost that framework choice cannot erase.
How do I prove a CU or size win?
Simulate identical transactions before and after, record p50/p99 unitsConsumed, compare release .so sizes, and lock limits in LiteSVM or CI.
Can Anchor and Pinocchio programs call each other?
Yes via CPI when account metas, ownership, layouts, and PDA seeds match what each side expects.
How do Kit clients talk to Pinocchio programs?
Build instruction data and account metas from Codama (or hand codecs). @solana/kit 7.0.0 needs correct wire formats, not Anchor specifically.
What is the safest migration strategy?
Freeze layouts and seeds, move the hot path behind CPI or a controlled upgrade, dual-run with tests, update client schemas, then tighten upgrade authority when metrics and review are clean.
When should a small team stay on Anchor?
Until simulated CU or size pain is concrete. Premature minimalism often costs more in missing IDL and validation bugs than it saves.
Does consensus latency change framework choice?
No. Confirmation timing is a client concern; CU metering and account models stay program-framework concerns.
What toolchain does this page pin?
Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, Rust 1.91.1, and @solana/kit 7.0.0. Re-benchmark after upgrades.
Where should I go next?
Lightweight Frameworks Overview, Pinocchio Basics, Building a Program with Pinocchio, Steel Framework, CU & Binary-Size Wins, and Interop & Migration.
Related
- Lightweight Frameworks Overview - why teams look past Anchor for efficiency
- Pinocchio Basics - entrypoint, accounts, and minimal patterns
- Building a Program with Pinocchio - dispatch, validation, and CPI structure
- Steel Framework - ergonomic middle ground between Pinocchio and Anchor
- CU & Binary-Size Wins - how to measure real efficiency gains
- Interop & Migration - CPI boundaries and moving between stacks
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.