New here? Start with the guided paths
Use the guided lessons to learn the three SolStudio surfaces before going deeper into the reference docs.
Open learning pathsGetting Started with SolStudio
SolStudio has three surfaces: the Visual Builder for designing Solana programs, the CLI for inspecting local Rust and IDL projects, and Cloud for running Solana automations. This guide focuses on the visual builder path.
Table of Contents
- 1The Canvas
- 2Creating Your First Program
- 3Node Types Overview
- 4Connecting Nodes
- 5Configuring Properties
- 6Generating Code
- 7Understanding the Output
- 8Workflow Tips
The Canvas
The editor is a node-based flow canvas powered by React Flow. You place nodes representing Solana program components and draw edges between them to define relationships.
Key concepts:
- Nodes represent program components: the program itself, instructions, accounts, states, constraints, logic operations, errors, events, and custom code.
- Edges (connections) define how these components relate. An edge from a Program node to an Instruction node means "this instruction belongs to this program."
- Handles are the small connection points on each node. Each handle accepts specific connection types.
Creating Your First Program
Step 1: Add a Program Node
Every flow starts with exactly one Program node. This is the root of your program definition.
- 1Drag a Program node from the node palette onto the canvas.
- 2In the Properties Panel (right sidebar), configure:
- **name** (snake_case): e.g., my_token
- **version**: e.g., 0.1.0
- programId: your on-chain program address (optional at design time)
- description: human-readable description
Step 2: Add Instructions
A Solana program is a collection of instructions. Each instruction is an entry point that client code can call.
- 1Drag an Instruction node onto the canvas.
- 2Connect it from the Program node's bottom handle to the Instruction node's top handle.
- 3Configure in the Properties Panel:
- **name** (snake_case): e.g., initialize, transfer, mint
- **args**: click to add instruction arguments (name + type pairs), e.g., amount: u64
- **accessControl**: none, admin_only, or custom
Step 3: Add Accounts
Each instruction operates on a set of accounts. These are the Solana accounts the instruction will read or modify.
- 1Drag an Account node onto the canvas.
- 2Connect it from the Instruction node's right handle to the Account node's top handle.
- 3Configure:
- **name** (snake_case): e.g., payer, vault, authority
- accountType: choose from the 14 account types (see below)
- **Flags**: toggle isMut, isSigner, isInit, isInitIfNeeded, isClose as needed
Step 4: Define State Structs
If your program stores data on-chain, define state structs.
- 1Drag a State node onto the canvas.
- 2Add fields with name and type (e.g.,
authority: Pubkey,balance: u64). - 3Connect the State node's right handle to the Account node's left handle to bind the account to this data structure.
Step 5: Add Logic
Logic nodes define what happens inside an instruction's body.
- 1Drag a Logic node onto the canvas.
- 2Connect it from the Instruction node's bottom handle to the Logic node's top handle.
- 3Choose the logic type (e.g.,
set-field,transfer-sol,require). - 4Configure parameters in the Properties Panel.
Step 6: Generate Code
- 1Select your target framework: Anchor, Pinocchio, or Quasar.
- 2Click Generate.
- 3The code panel shows the complete Rust project with all files.
Node Types Overview
| Node Type | Purpose | Connects From | Connects To |
|---|---|---|---|
| Program | Root node defining the program | -- | Instructions |
| Instruction | A program instruction handler | Program | Accounts, Logic, Errors, Events, Custom Code |
| Account | An account passed to an instruction | Instruction | Constraints, State |
| State | On-chain data struct definition | -- | Accounts |
| Constraint | Validation rule for an account | Account | -- |
| Logic | Operation in instruction body | Instruction or Logic | Logic (for if-else bodies) |
| Error | Custom error variant | Instruction | -- |
| Event | Event that can be emitted | Instruction | -- |
| Custom Code | Raw Rust code injection | Instruction or Logic | -- |
| Integration | Plugin integration point | Instruction | Accounts |
Connecting Nodes
Connections enforce rules. The editor only allows valid connections:
- 1Drag from an output handle (right side or bottom of a node) to an input handle (left side or top of another node).
- 2Handles are color-coded and labeled. A handle will highlight when a compatible connection is possible.
- 3Invalid connections are rejected automatically.
See connection-rules.md for the complete connection reference.
Configuring Properties
Select any node to see its properties in the Properties Panel on the right side of the editor.
Common Properties
- name: Identifier for the node. Must follow naming conventions:
- snake_case for instructions, accounts, fields, constraints
- PascalCase for state structs, errors, events
- description: Optional documentation string
Account Flags
Account nodes have toggle flags that control behavior:
| Flag | Meaning |
|---|---|
isMut | The instruction will write to this account |
isSigner | This account must sign the transaction |
isInit | Create this account during the instruction |
isInitIfNeeded | Create this account only if it does not exist |
isClose | Close this account and reclaim its rent |
Additional fields appear contextually:
- When
isInitorisInitIfNeededis set: payer (who pays rent) and space (account size in bytes, or "auto") - When
isCloseis set: closeTarget (where the lamports go) - When
accountTypeistoken-account: tokenAuthority and tokenMint - When
accountTypeismint: mintAuthority and mintDecimals - When
accountTypeisassociated-token: associatedAuthority and associatedMint - When
accountTypeisunchecked-account: safetyComment (required safety justification)
Constraint Nodes
Instead of using flags, you can attach explicit Constraint nodes to an Account for fine-grained control. Constraint nodes have their own configuration parameters. See flags-and-constraints.md for details.
Logic Nodes
Logic nodes have type-specific parameters:
| Logic Type | Key Parameters |
|---|---|
set-field | account, field, value |
transfer-sol | from, to, amount |
transfer-token | from, to, authority, amount |
mint-to | mint, to, authority, amount |
burn | mint, from, authority, amount |
require | condition, errorCode |
if-else | condition (then/else bodies via child connections) |
emit-event | event name, field values |
return-error | errorCode |
math | operation (add/sub/mul/div/mod), left, right, result, checked |
cpi | targetProgram, instruction, accounts, data |
custom-code | code (raw Rust), inputs, outputs |
Generating Code
Click the framework selector in the toolbar and choose:
Anchor
The standard Solana framework. Generates a full Anchor project with:
Cargo.tomlwith anchor-lang and optional anchor-spl dependenciessrc/lib.rswith#[program]module anddeclare_id!src/instructions/<name>.rsper instruction (handler + Accounts struct)src/state/<name>.rsper state struct with#[account]derivesrc/errors.rswith#[error_code]enumsrc/events.rswith#[event]structssrc/constants.rsfor program constants
Best for: most Solana programs, projects that benefit from Anchor's IDL generation, accounts struct validation, and the Anchor ecosystem.
Pinocchio
A no_std, zero-dependency, compute-optimized framework. Generates:
Cargo.tomlwith pinocchio, pinocchio-system, pinocchio-token dependenciessrc/lib.rswithprogram_entrypoint!and discriminator-based dispatchsrc/instructions/<name>.rsper instruction with manual account validationsrc/state/<name>.rsper state with zero-copy byte-offset accessorssrc/errors.rswithFrom<T> for ProgramErrorconversionsrc/utils.rswith PDA verification helper (only when PDA seeds are used)
Best for: high-performance programs, compute-unit optimization, programs that need minimal dependencies.
Quasar
A zero-copy, no_std framework with Anchor-like ergonomics. Generates:
Cargo.tomlwith quasar-lang dependencysrc/lib.rswith#[program]block containing inline instruction logicsrc/instructions/<name>.rsper instruction (Accounts struct only)src/state/<name>.rsper state with Pod types and explicit discriminatorssrc/errors.rswith#[error_code]enum
Best for: developers wanting zero-copy performance with Anchor-style syntax.
Understanding the Output
File Structure (Anchor Example)
programs/my_program/
Cargo.toml
src/
lib.rs -- program entry, #[program] mod
instructions/
mod.rs -- pub mod initialize; pub mod transfer;
initialize.rs -- handler fn + Accounts struct
transfer.rs
state/
mod.rs
vault.rs -- #[account] struct Vault { ... }
errors.rs -- #[error_code] enum MyProgramError { ... }
events.rs -- #[event] structs
constants.rs -- pub const valuesWarnings and Errors
After generation, the code panel shows:
- Warnings: non-fatal issues like "Instruction has no accounts"
- Errors: fatal issues that prevented generation
Workflow Tips
- 1Start with the Program node. Every flow needs exactly one.
- 2Name things carefully. Names become Rust identifiers. Use snake_case for instructions/accounts and PascalCase for state/error/event names. Rust keywords are not allowed.
- 3Use auto space. When initializing an account with a state type, set space to "auto" to let the framework calculate the correct size.
- 4Prefer flags for simple cases. Use the isMut/isSigner/isInit toggles on Account nodes for common patterns. Use explicit Constraint nodes only when you need fine-grained control.
- 5**Chain logic nodes.** Connect logic nodes in sequence (top to bottom) to control execution order. Use the
orderproperty to enforce ordering. - 6Use if-else for branching. Connect child logic nodes to the if-else node's bottom handle for the "then" branch, and to the "else-out" handle for the "else" branch.
- 7Always add Error nodes. Custom errors make debugging easier. Define them with error codes starting at 6000 and connect them to the instructions that use them.
- 8Check the generated code. Review the output, especially for custom-code blocks and CPI calls, which may need manual adjustment.
- 9Iterate visually. Modify nodes and connections, then regenerate. The visual flow is the single source of truth.