← Back to templates

Expo Kit Pinocchio example

A template for building a Solana mobile app with Expo, React Native, Solana Kit, Pinocchio, and Uniwind.

Preview of Expo Kit Pinocchio example

expo-kit-pinocchio

This is an Expo project pre-configured with a Pinocchio program, Uniwind for styling, and Solana libraries.

Technologies

Get started

  1. Install dependencies

    npm install
  2. Start the app

This steps builds the dependencies for the development client.

npm run android

In the output, you'll find options to open the app in a:

You can start developing by editing the files inside the app directory. This project uses file-based routing.

The Pinocchio program

The program directory contains a Solana program called hello_world, written with Pinocchio, a zero-dependency library for writing Solana programs without a framework. It's a small counter where every wallet gets its own counter account, derived from the wallet address (seeds = [b"counter", wallet]) — use it as the starting point for your own program: search for hello_world (and HelloWorld/helloWorld) to find everything to rename.

Working on the program requires the Rust and Solana toolchains.

  1. Generate a program keypair and set the program ID

    The program ID in the source is a placeholder. This generates your own keypair, writes its address into declare_id!, rebuilds the program so the IDL carries the new address, and regenerates the TypeScript client from it:

    npm run program:setup
  2. Build and test the program

    npm run program:test

    This builds the program with cargo build-sbf and runs the Rust tests in program/programs/hello_world/tests against it with LiteSVM, an in-process validator.

The generated TypeScript client

The app talks to the program through a fully typed client generated by Codama. The #[codama(...)] attributes in the program describe its instructions, accounts, PDAs, and errors, and build.rs turns them into the IDL in program/target/idl on every build. The client lives in program/src/client/js/generated and only depends on @solana/kit. Import it anywhere in the app via the @project/program alias:

import { fetchCounter, getIncrementInstructionAsync, HELLO_WORLD_PROGRAM_ADDRESS } from '@project/program'

After changing the program, rebuild the IDL and regenerate the client:

npm run program:build
npm run codama:js

Add hand-written wrappers around the generated code in program/src/client/js/index.ts — the generated directory is overwritten on every run.

Using the program from the app

The home screen includes a counter feature (src/features/counter) that talks to the program through the generated client and Mobile Wallet Adapter. Each connected wallet initializes and increments its own counter. The app connects to devnet, so deploy the program there before using it:

npm run program:deploy:devnet

Your deploy wallet needs devnet SOL — get some from faucet.solana.com. The wallet in the app needs a small amount of devnet SOL too, to pay for the counter account and transaction fees.

Develop against localnet

For a faster loop you can run everything against a local validator, forwarded to your device over adb:

  1. Start the localnet and keep it running: npm run program:localnet
  2. Deploy the program to it: npm run program:deploy:localnet
  3. Switch the network to Localnet with the selector in the app
  4. Connect your wallet and tap Request Airdrop to fund it

Two things to know: localnet needs a debug build — npm run android makes one, and Android debug builds allow the cleartext http://localhost endpoint while release builds only talk HTTPS. And the regular Seeker wallet only signs for public clusters, so signing on localnet requires a localnet-capable wallet such as fakewallet.

Learn more

To learn more about developing your project with Expo, look at the following resources:

© 2026 Solana Foundation. All rights reserved.