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.
Search across all documentation pages
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.
.so), IDL / Codama, entrypoint, manual validation, CPI interop, hot-path rewrite.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:
entrypoint!(process_instruction).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.
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 ProgramErrorEntrypoint 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.
.so size.If Token CPI dominates, fix algorithm or account design before shopping frameworks.
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.
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 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.
Attach simulate numbers to a short ADR so the next rewrite debate starts from data.
.so files affect deploy cost and ops friction.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.
Some programs hit CU ceilings, deploy size limits, or audit preferences for explicit checks; thinner stacks trade convenience for control on those paths.
No. Anchor 0.32.1 remains the default velocity stack; lightweight frameworks are specialized tools, not a universal replacement.
Same general model (entrypoint, accounts, manual validation) with a focused crate API aimed at lower overhead and a tighter dependency tree.
Between Pinocchio and Anchor: more structure than raw Pinocchio, less macro/IDL weight than Anchor. Profile it; do not assume free CU.
Usually no. Token CPI and syscalls have inherent cost that framework choice cannot erase.
Simulate identical transactions before and after, record p50/p99 unitsConsumed, compare release .so sizes, and lock limits in LiteSVM or CI.
Yes via CPI when account metas, ownership, layouts, and PDA seeds match what each side expects.
Build instruction data and account metas from Codama (or hand codecs). @solana/kit 7.0.0 needs correct wire formats, not Anchor specifically.
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.
Until simulated CU or size pain is concrete. Premature minimalism often costs more in missing IDL and validation bugs than it saves.
No. Confirmation timing is a client concern; CU metering and account models stay program-framework concerns.
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.
Lightweight Frameworks Overview, Pinocchio Basics, Building a Program with Pinocchio, Steel Framework, CU & Binary-Size Wins, and Interop & Migration.
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.
Reviewed by Chris St. John·Last updated Jul 15, 2026