Your First Stack
In this tutorial, you’ll build an end-to-end real-time data pipeline in 15 minutes. We’ll create a “Counter” stack that tracks on-chain increment events and displays the live count in a React app.
What You’ll Build
Section titled “What You’ll Build”A full-stack streaming application consisting of:
- A Rust Spec: Defines how to transform on-chain Solana events into a “Counter” entity.
- A Cloud Deployment: A managed Hyperstack instance that processes the stream.
- A React Frontend: A live dashboard that updates instantly as on-chain events occur.
Part 1: Create the Spec (Rust)
Section titled “Part 1: Create the Spec (Rust)”The “Spec” is the heart of your stack. It tells Hyperstack which on-chain data to watch and how to project it into a useful state.
1. Create a new Rust project
Section titled “1. Create a new Rust project”cargo new counter-spec --libcd counter-spec2. Add dependencies
Section titled “2. Add dependencies”Add hyperstack to your Cargo.toml:
[dependencies]hyperstack = "0.1"serde = { version = "1.0", features = ["derive"] }3. Write your spec
Section titled “3. Write your spec”Open src/lib.rs and define your projection. For this tutorial, we’ll assume a simple Solana program with a CounterAccount and an Increment instruction.
use hyperstack::{hyperstack, Stream, Strategy};
#[hyperstack(idl = "counter_idl.json")]pub mod counter_stack { use super::*;
#[entity] #[derive(Stream)] pub struct Counter { #[map(from = "CounterAccount", field = "authority", primary_key = true)] pub owner: String,
#[aggregate(from = "Increment", field = "amount", strategy = Sum)] pub total_count: u64,
#[derive_from(from = "Increment", field = "__timestamp")] pub last_updated: i64, }}4. Build to generate AST
Section titled “4. Build to generate AST”Hyperstack uses AST serialization. When you compile your code, it automatically generates a .hyperstack/Counter.ast.json file.
cargo buildPart 2: Deploy to Hyperstack Cloud
Section titled “Part 2: Deploy to Hyperstack Cloud”Now let’s push your spec to the cloud. Hyperstack manages the infrastructure, so you don’t need to worry about scaling or WebSocket servers.
1. Login to the CLI
Section titled “1. Login to the CLI”hs auth login2. Initialize your project
Section titled “2. Initialize your project”This creates a hyperstack.toml file that links your local AST to the cloud.
hs config init3. Push and Deploy
Section titled “3. Push and Deploy”The up command is a shortcut that pushes your AST, builds the container, and deploys it to a global cluster.
hs up counter-stackExpected Output:
✔ Spec pushed (v1)✔ Build created (id: bld_123...)✔ Build completed🚀 Deployed to: wss://counter-stack.stack.hypertek.appPart 3: Connect from React
Section titled “Part 3: Connect from React”Finally, let’s build the frontend. We’ll use the Hyperstack React SDK to subscribe to live updates.
1. Set up your React app
Section titled “1. Set up your React app”npx create-react-app my-counter-app --template typescriptcd my-counter-appnpm install hyperstack-react zustand2. Configure the Provider
Section titled “2. Configure the Provider”Wrap your app in HyperstackProvider using the URL you got from the previous step.
import { HyperstackProvider } from 'hyperstack-react';
const root = ReactDOM.createRoot(document.getElementById('root')!);root.render( <HyperstackProvider websocketUrl="wss://counter-stack.stack.hypertek.app"> <App /> </HyperstackProvider>);3. Define the Stack
Section titled “3. Define the Stack”Tell the React SDK about your “Counter” entity.
import { defineStack, createListView } from 'hyperstack-react';
export interface Counter { owner: string; total_count: number; last_updated: number;}
export const CounterStack = defineStack({ name: 'counter-stack', views: { counters: { list: createListView<Counter>('Counter/list'), }, },});4. Build the Component
Section titled “4. Build the Component”Create a component that displays the live data.
import { useHyperstack } from 'hyperstack-react';import { CounterStack } from './stack';
export default function App() { const stack = useHyperstack(CounterStack); const { data: counters, isLoading } = stack.views.counters.list.use();
if (isLoading) return <div>Connecting to stream...</div>;
return ( <div> <h1>Live Counters</h1> {counters?.map((c) => ( <div key={c.owner} style={{ padding: '1rem', border: '1px solid #ccc' }}> <h3>Owner: {c.owner}</h3> <p>Count: <strong>{c.total_count}</strong></p> <small>Last updated: {new Date(c.last_updated * 1000).toLocaleString()}</small> </div> ))} </div> );}Troubleshooting
Section titled “Troubleshooting””AST file not found”
Section titled “”AST file not found””Ensure you ran cargo build in your Rust project. The #[hyperstack] macro generates the AST file during compilation.
WebSocket connection fails
Section titled “WebSocket connection fails”- Check that the URL matches the output of
hs up. - Ensure your spec is successfully deployed by running
hs deploy list.
Data is not appearing
Section titled “Data is not appearing”- Verify that your Solana program is actually emitting the events or updating the accounts defined in your spec.
- Check the browser console for any subscription errors.
Next Steps
Section titled “Next Steps”- Learn more about Spec Macros to build complex pipelines.
- Explore View Strategies for different data access patterns.
- Check the CLI Reference for advanced deployment options.