The Solana mainnet deploy came in at $141. For a demo project. I stopped, recalculated, and stared at the number for a minute.
I'd built the tip jar in Anchor 0.32.1 — the standard framework, the one with real docs, the one everyone reaches for first. It worked. Seven integration tests passed. Then I checked the binary before committing 1.6 SOL to mainnet: 230 KB.
Three options, one decision
On Solana, accounts need to hold enough SOL to cover two years of rent to become rent-exempt, otherwise the runtime can garbage-collect them. For a program account, that's about 6,960 lamports per byte. At ~$86/SOL, 230 KB works out to ~1.64 SOL — $141.
You can close a Solana program later and reclaim that SOL to a recipient wallet. So it's not technically unrecoverable. But "recoverable in theory" doesn't change what you need in your wallet before you can deploy.
| Option | Binary size | Approx. cost |
|---|---|---|
| Anchor 0.32.1, unoptimised | 230 KB | ~$141 |
Anchor + opt-level = "z", lto = true, strip = "symbols"
|
~90–100 KB | ~$60 |
| Pinocchio rewrite | 15–20 KB (estimation) | ~$9 |
Anchor with size flags was 15 minutes of work. Those flags strip symbols and merge compilation units — they don't touch Anchor's macro overhead. There's a floor, and $60 is still a lot for a demo. I went with Pinocchio.
What Pinocchio actually is
Pinocchio is a zero-dependency Rust framework for Solana programs. No macros, no IDL, no borsh. You write the discriminator logic, the account parsing, the PDA derivation — all of it.
Where Anchor's #[derive(Accounts)] generates validation from a handful of attributes with a lot happening out of sight, Pinocchio puts every check in explicit byte-offset reads. Nothing is invisible. The price for that is verbosity. The reason to pay it is binary size.
The rewrite
Four hours. Three instructions (initialize, send_support, withdraw) and three account types (MessageBoard PDA, Vault PDA, per-message Support PDA). I wrote the byte layout manually, encoded fields by hand, checked boundaries explicitly.
The 7/7 tests passed at the end. Worth noting: since Pinocchio generates no IDL, the TypeScript tests couldn't use Anchor's program.methods.sendSupport().rpc() style. Every instruction had to be built as a raw TransactionInstruction — manual Buffer.concat, explicit account list, correct discriminator byte. So the actual scope of the work was the Rust rewrite plus rewriting the test client from scratch.
Tests ran against a live solana-test-validator with the Pinocchio binary pre-loaded. No Anchor runner.
Binary: 30 KB. Above the 15–20 KB estimate — the manual validation boilerplate adds code that Anchor macros would have inlined. Still 87% smaller than the Anchor build.
Actual mainnet deploy: 0.214 SOL. ~$18. Within 1% of the rent calculation I'd done upfront.
| Build | Binary size | Deploy cost |
|---|---|---|
| Anchor 0.32.1 | 230 KB | ~$141 (never deployed to mainnet) |
| Pinocchio 0.9 — estimated | ~15–20 KB | ~$9 |
| Pinocchio 0.9 — actual | 30 KB | $18 |
The rubric gap
My scoring rubric has a dimension for per-message transaction cost (D7) and one for deployment experience (D6). There's no dimension for the developer's one-time deploy cost.
On EVM weeks — Base, Scroll — this never came up. Both cost cents. On Solana, after the optimisation, it was $18. Before: $141. That's a real number with no rubric home. Worth flagging, because a methodology that doesn't measure something can't be honest about it.
Top comments (0)