Built on pinocchio · no_std · v0.24.0

Solana programs without the framework tax.

Pina gives you macros, typed accounts, and generated clients, then compiles to the smallest binaries of any Solana framework. Compute stays at hand-written cost, and deployed programs evolve through managed ABI migrations.

cargo add pina
use pina::*;

declare_id!("GJQcuWrT2f3f4KNuJcXhhwUa1ZQTYbxzzJ1hotzKu8hS");

#[discriminator(entrypoint)]
pub enum CounterInstruction {
    Initialize = 0,
    Increment = 1,
}

#[discriminator]
pub enum CounterAccountType {
    CounterState = 1,
}

// 11 bytes on-chain: discriminator, version, bump, count.
#[account(discriminator = CounterAccountType)]
#[pda(seeds = [SEED_COUNTER, authority: Address], bump = bump)]
pub struct CounterState {
    pub bump: u8,
    pub count: u64,
}
360 CU per increment 1-byte discriminators 0 heap allocations
  • 1,616bytes

    Hello world, deployed

    49% smaller than hand-written Pinocchio.

  • 46×

    Smaller than Anchor v1

    The same program is 74,416 bytes in Anchor v1.

  • 360CU

    Per counter increment

    29× less compute than Anchor v1.

  • 0

    Heap allocations

    Every on-chain crate is no_std with no allocator.

Measured in a Mollusk VM with cargo build-sbf --lto. Methodology

Why Pina

Framework ergonomics, hand-written output.

Macros stay minimal and predictable. The IDL is inferred from the validation code you already write, so payer.assert_signer()? becomes a signer constraint without a second source of truth.

Only in Pina

Managed ABI migrations

Version envelopes, generated transitions, and a publication ledger evolve account and instruction schemas without breaking deployed programs or the clients that read them.

How migrations flow
  1. v0CounterStatebump · countpublished
  2. v1+ authoritygenerated transitionpublished
  3. v2+ last_updatedclients decode every versioncurrent

no_std, allocation-free

Every on-chain crate compiles to the bpfel-unknown-none SBF target with no heap and no allocator.

Validated zero-copy

PinaPod validates account bytes before Pina hands you an in-place, typed view. No copies, no heap.

One-byte discriminators

Accounts, instructions, and events carry a typed discriminator as their first field, one byte by default and up to u64 when you need it.

Declarative validation

Chain checks on any account, or compile #[pina(validate(...))] rules into allocation-free code.

payer.assert_signer()?
     .assert_writable()?;

Typed clients in every language you ship

Extract a Codama IDL with pina idl and generate Rust, TypeScript, and Dart clients, or a CPI crate for other programs to call yours.

  • Rust
  • TypeScript
  • Dart
  • CPI crates

Benchmarks

Measured, not claimed.

The same hello-world and counter programs, written in five frameworks, built under one release profile, and executed in a Mollusk VM. Hand-written Pinocchio is the floor a framework has to justify. Lower is better.

Hello world: deployed program size

Bytes of the deployed .so · lower is better

  1. Pina (unchecked hello)0.23.0 1,392−14% vs Pina
  2. Pina0.23.0 1,616
  3. Quasarrev 863ee77 1,880+16% vs Pina
  4. Anchor v2 (lang-v2)2.0.0-rc.2 2,456+52% vs Pina
  5. Pinocchio (hand-written)0.11.2 3,160+96% vs Pina
  6. Anchor v11.2.2 74,41646× Pina
Bars past a break are drawn to a shortened scale; their full value is printed. Methodology and caveats →
View the measurements as a table
Hello world
FrameworkVersionSize (bytes)hello CUvs Pinocchio size
Pina0.23.01,616136−49%
Pina (unchecked hello)0.23.01,392117−56%
Pinocchio (hand-written)0.11.23,160111+0%
Quasarrev 863ee771,880119−41%
Anchor v11.2.274,416421+2255%
Anchor v2 (lang-v2)2.0.0-rc.22,456152−22%
Counter
FrameworkVersionSize (bytes)initialize CUincrement CUvs Pinocchio size
Pina0.23.07,5921,694360+17%
Pina (SIMD-0312)0.23.06,3761,705360−2%
Pinocchio (hand-written)0.11.26,5121,4901,721+0%
Quasarrev 863ee7712,0563,4741,134+85%
Anchor v11.2.2139,49612,67310,391+2042%
Anchor v2 (lang-v2)2.0.0-rc.210,7523,5182,165+65%

Comparison

Everything you expect, plus what nobody else ships.

CapabilityPinav0.24.0Anchor v11.2.2Anchor v2 (lang-v2)2.0.0-rc.2Quasarrev 863ee77
IDL generated from source
Declarative account validation
Typed generated clientsRust · JS/TS · Dart · CPI cratesTS · Rust CPIRust · TS (alpha)Rust · JS · Solana Kit
no_std on-chain runtimeallocation-freestd + heapallocator by defaultzero-allocation
Validated zero-copy accountsvalidated viewsopt-in AccountLoaderPod accounts by defaultpointer-cast views
One-byte discriminatorsdefault (u8–u64)8-byte hashopt-in
Managed ABI migrationsversion envelopes · transitions · publication ledgeroff-chain migrate script only
Versioned eventsevery released schema decodable by clients
Security lints on program sourcepina lint
CU profilerstatic .so analysistrace flamegraphs onlyshares the Anchor CLIstatic + flamegraph
Upgrade rehearsal before deploypina deploy --rehearse

First-class Partial Not available

Get started

Your first program in three commands.

  1. 1

    Install the CLI

    Prebuilt for macOS, Linux, Windows, and FreeBSD. Or cargo install pina_cli.

    npm install --global @pina-rs/cli
  2. 2

    Scaffold a program

    A no_std program, a typed starter instruction, and host and Surfpool tests.

    pina init my_program
  3. 3

    Build and test

    Compile to SBF with the Agave toolchain, then run the scaffold’s tests.

    cd my_program && pina build && pina test