DocsGetting Started
SolStudio

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 paths

Getting 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

  1. 1The Canvas
  2. 2Creating Your First Program
  3. 3Node Types Overview
  4. 4Connecting Nodes
  5. 5Configuring Properties
  6. 6Generating Code
  7. 7Understanding the Output
  8. 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.

  1. 1Drag a Program node from the node palette onto the canvas.
  2. 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.

  1. 1Drag an Instruction node onto the canvas.
  2. 2Connect it from the Program node's bottom handle to the Instruction node's top handle.
  3. 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.

  1. 1Drag an Account node onto the canvas.
  2. 2Connect it from the Instruction node's right handle to the Account node's top handle.
  3. 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.

  1. 1Drag a State node onto the canvas.
  2. 2Add fields with name and type (e.g., authority: Pubkey, balance: u64).
  3. 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.

  1. 1Drag a Logic node onto the canvas.
  2. 2Connect it from the Instruction node's bottom handle to the Logic node's top handle.
  3. 3Choose the logic type (e.g., set-field, transfer-sol, require).
  4. 4Configure parameters in the Properties Panel.

Step 6: Generate Code

  1. 1Select your target framework: Anchor, Pinocchio, or Quasar.
  2. 2Click Generate.
  3. 3The code panel shows the complete Rust project with all files.

Node Types Overview

Node TypePurposeConnects FromConnects To
ProgramRoot node defining the program--Instructions
InstructionA program instruction handlerProgramAccounts, Logic, Errors, Events, Custom Code
AccountAn account passed to an instructionInstructionConstraints, State
StateOn-chain data struct definition--Accounts
ConstraintValidation rule for an accountAccount--
LogicOperation in instruction bodyInstruction or LogicLogic (for if-else bodies)
ErrorCustom error variantInstruction--
EventEvent that can be emittedInstruction--
Custom CodeRaw Rust code injectionInstruction or Logic--
IntegrationPlugin integration pointInstructionAccounts

Connecting Nodes

Connections enforce rules. The editor only allows valid connections:

  1. 1Drag from an output handle (right side or bottom of a node) to an input handle (left side or top of another node).
  2. 2Handles are color-coded and labeled. A handle will highlight when a compatible connection is possible.
  3. 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:

FlagMeaning
isMutThe instruction will write to this account
isSignerThis account must sign the transaction
isInitCreate this account during the instruction
isInitIfNeededCreate this account only if it does not exist
isCloseClose this account and reclaim its rent

Additional fields appear contextually:

  • When isInit or isInitIfNeeded is set: payer (who pays rent) and space (account size in bytes, or "auto")
  • When isClose is set: closeTarget (where the lamports go)
  • When accountType is token-account: tokenAuthority and tokenMint
  • When accountType is mint: mintAuthority and mintDecimals
  • When accountType is associated-token: associatedAuthority and associatedMint
  • When accountType is unchecked-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 TypeKey Parameters
set-fieldaccount, field, value
transfer-solfrom, to, amount
transfer-tokenfrom, to, authority, amount
mint-tomint, to, authority, amount
burnmint, from, authority, amount
requirecondition, errorCode
if-elsecondition (then/else bodies via child connections)
emit-eventevent name, field values
return-errorerrorCode
mathoperation (add/sub/mul/div/mod), left, right, result, checked
cpitargetProgram, instruction, accounts, data
custom-codecode (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.toml with anchor-lang and optional anchor-spl dependencies
  • src/lib.rs with #[program] module and declare_id!
  • src/instructions/<name>.rs per instruction (handler + Accounts struct)
  • src/state/<name>.rs per state struct with #[account] derive
  • src/errors.rs with #[error_code] enum
  • src/events.rs with #[event] structs
  • src/constants.rs for 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.toml with pinocchio, pinocchio-system, pinocchio-token dependencies
  • src/lib.rs with program_entrypoint! and discriminator-based dispatch
  • src/instructions/<name>.rs per instruction with manual account validation
  • src/state/<name>.rs per state with zero-copy byte-offset accessors
  • src/errors.rs with From<T> for ProgramError conversion
  • src/utils.rs with 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.toml with quasar-lang dependency
  • src/lib.rs with #[program] block containing inline instruction logic
  • src/instructions/<name>.rs per instruction (Accounts struct only)
  • src/state/<name>.rs per state with Pod types and explicit discriminators
  • src/errors.rs with #[error_code] enum

Best for: developers wanting zero-copy performance with Anchor-style syntax.


Understanding the Output

File Structure (Anchor Example)

bash
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 values

Warnings 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

  1. 1Start with the Program node. Every flow needs exactly one.
  2. 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.
  3. 3Use auto space. When initializing an account with a state type, set space to "auto" to let the framework calculate the correct size.
  4. 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. 5**Chain logic nodes.** Connect logic nodes in sequence (top to bottom) to control execution order. Use the order property to enforce ordering.
  6. 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.
  7. 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.
  8. 8Check the generated code. Review the output, especially for custom-code blocks and CPI calls, which may need manual adjustment.
  9. 9Iterate visually. Modify nodes and connections, then regenerate. The visual flow is the single source of truth.