How It Works
Hyperstack is a declarative data layer for Solana. You define the data shape you need, and Hyperstack handles all the infrastructure to stream it to your app.
The Problem
Section titled “The Problem”Building data pipelines for Solana apps is painful:
- Manual parsing - You write custom code to decode accounts and instructions
- ETL complexity - You build pipelines to transform, aggregate, and store data
- RPC overhead - You manage websocket connections, retries, and state sync
- Type mismatches - On-chain types don’t match your app types
Most teams spend weeks on infrastructure before shipping features.
The Hyperstack Solution
Section titled “The Hyperstack Solution”Instead of building infrastructure, you declare what data you need:
#[entity(name = "Token")]pub struct Token { #[from_instruction(Create::mint, primary_key)] pub mint: String,
#[map(BondingCurve::virtual_sol_reserves)] pub sol_reserves: u64,
#[aggregate(from = Buy, field = amount, strategy = Sum)] pub total_volume: u64,}Hyperstack then:
- Subscribes to the relevant on-chain events
- Transforms raw data into your entity shape
- Streams updates to your app as they happen on-chain
- Generates type-safe SDKs for your frontend
Architecture Overview
Section titled “Architecture Overview”┌──────────────────────────────────────────────────────────────┐│ YOUR APP ││ React hooks, TypeScript streams, or raw WebSocket │└──────────────────────────────────────────────────────────────┘ ▲ │ WebSocket (live updates) ▼┌──────────────────────────────────────────────────────────────┐│ HYPERSTACK CLOUD ││ ││ ┌────────────┐ ┌────────────┐ ┌────────────┐ ││ │ Compiler │ -> │ VM │ -> │ Streamer │ ││ └────────────┘ └────────────┘ └────────────┘ ││ ^ ^ │ ││ AST Bytecode State Tables WebSocket ││ ││ ┌────────────────────────────────────────────────────┐ ││ │ Yellowstone gRPC │ ││ │ (Live Solana data feed) │ ││ └────────────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────────────┘ ▲ │ Yellowstone gRPC (raw transactions) ▼┌──────────────────────────────────────────────────────────────┐│ SOLANA ││ On-chain programs emitting transactions and state changes │└──────────────────────────────────────────────────────────────┘Key Concepts
Section titled “Key Concepts”Stacks
Section titled “Stacks”A Stack is a deployed data pipeline that:
- Declares one or more Solana programs it cares about — each with its own IDL
- Subscribes to on-chain events across all of those programs
- Transforms raw transaction data into structured entities
- Aggregates values over time (sums, counts, etc.)
- Streams updates to connected clients as they happen
A stack isn’t limited to a single program. You can pull data from multiple programs into a single unified set of entities — as long as you provide an IDL for each. For example, a DeFi stack might combine instructions from a DEX program, a token program, and a rewards program into one coherent stream.
Think of it as a “live query” across Solana — you declare the programs and data shape you need, and Hyperstack keeps it updated.
Entities
Section titled “Entities”An Entity is a structured object representing on-chain state. A stack can contain multiple entities — for example, a DeFi stack might have separate entities for pools, positions, and trades. Each entity has:
- Primary key - Unique identifier (usually a pubkey)
- Fields - Data attributes with population strategies
- Sections - Logical groupings of fields
#[entity(name = "Token")]pub struct Token { pub id: TokenId, // Primary key section pub info: TokenInfo, // Metadata section pub trading: Trading, // Metrics section}Mappings
Section titled “Mappings”Mappings define how on-chain data flows into entity fields:
| Mapping Type | Source | Example |
|---|---|---|
#[map] | Account field | #[map(BondingCurve::reserves)] |
#[from_instruction] | Instruction arg/account | #[from_instruction(Create::mint)] |
#[snapshot] | Account snapshot | #[snapshot(from = Account)] |
#[derive_from] | Derive from instruction | #[derive_from(from = Buy, field = user)] |
#[aggregate] | Computed from events | #[aggregate(from = Buy, strategy = Sum)] |
#[event] | Captured instruction | #[event(strategy = Append)] |
#[computed] | Derived from fields | #[computed(field_a + field_b)] |
Population Strategies
Section titled “Population Strategies”Strategies control how field values are updated:
| Strategy | Behavior |
|---|---|
SetOnce | Set once, never overwrite |
LastWrite | Always use latest value |
Append | Collect into array |
Sum | Running total |
Count | Event counter |
UniqueCount | Count unique values |
Max / Min | Track extremes |
Views are how you access data from a stack. By default, every entity gets two built-in views:
| Mode | Path | Returns | Use Case |
|---|---|---|---|
list | Entity/list | Array of entities | All entities |
state | Entity/state | Single entity | Get by key |
// List - all tokens as arrayconst { data: tokens } = stack.views.tokens.list.use();
// State - single token by keyconst { data: token } = stack.views.tokens.state.use({ key: mintAddress });Custom Views: If you need different sorting, filtering, or aggregation logic, you can define custom views using the #[view] macro in your stack specification. This lets you create specialized access patterns beyond the default list and state views.
Stack SDKs
Section titled “Stack SDKs”A Stack SDK is a generated package that tells the Hyperstack client how to interact with a specific feed. It contains:
- Entity types — The shape of your data
- View definitions — How to access entities (list, state, etc.)
- Helpers — Shared formatting and transformation logic
You can share generated SDKs with your team or publish them to npm/crates.io.
Data Flow
Section titled “Data Flow”Specification Time
Section titled “Specification Time”- Write stream definition using Rust macros
- Build generates stack spec (
.hyperstack/*.stack.json) - Deploy with
hs up - Cloud compiles spec to bytecode
Client
Section titled “Client”- Connect to WebSocket
- Subscribe to views
- Receive live updates
- React components re-render automatically
Live Updates
Section titled “Live Updates”Unlike traditional APIs where you poll for changes, Hyperstack pushes updates to you.
Update Types
Section titled “Update Types”| Type | Meaning |
|---|---|
upsert | Entity was created or updated |
delete | Entity was removed |
for await (const update of hs.views.token.list.watch()) { if (update.type === "upsert") { console.log("Token changed:", update.data); } else if (update.type === "delete") { console.log("Token removed:", update.key); }}Connection Lifecycle
Section titled “Connection Lifecycle”disconnected → connecting → connected → (reconnecting) → connected ↘ error| State | Meaning |
|---|---|
disconnected | Not connected |
connecting | Establishing WebSocket connection |
connected | Active and receiving updates |
reconnecting | Connection lost, attempting to restore |
error | Failed to connect (check URL, network) |
The SDK handles reconnection automatically. Your subscriptions resume when the connection is restored.
Type Safety
Section titled “Type Safety”Hyperstack provides end-to-end type safety:
- Spec types - Rust ensures valid mappings at compile time
- Generated types - SDK types match your entity definitions
- Runtime types - Data arrives pre-shaped, no parsing needed
// TypeScript knows token.mint is string, token.volume is bigintconst { data: token } = stack.views.tokens.state.use({ key });console.log(token.mint); // stringconsole.log(token.volume); // bigintNext Steps
Section titled “Next Steps”- Quickstart - Scaffold a working app in under 2 minutes
- Connect to a Stack - Add Hyperstack to your existing project
- React SDK - Build a complete React app
- TypeScript SDK - Framework-agnostic SDK
- Rust SDK - Native Rust client
- Building Stacks - Create custom data streams
- CLI Commands - Deployment and management