---
title: "How It Works"
description: "Architecture, core concepts, and data flow in Arete."
editUrl: true
head: []
template: "doc"
sidebar: {"order":3,"hidden":false,"attrs":{}}
pagefind: true
draft: false
---

Arete is a declarative data layer for Solana. You define the data shape you need, and Arete handles all the infrastructure to stream it to your app.

:::tip[Prefer AI-assisted development?]
You don't need to understand all of this to build with Arete. Check out the [Build with AI](/agent-skills/overview/) path to get started with prompts instead of code.
:::

---

## The Problem

Building data pipelines for Solana apps is painful:

1. **Manual parsing** - You write custom code to decode accounts and instructions
2. **ETL complexity** - You build pipelines to transform, aggregate, and store data
3. **RPC overhead** - You manage websocket connections, retries, and state sync
4. **Type mismatches** - On-chain types don't match your app types

Most teams spend weeks on infrastructure before shipping features.

---

## The Arete Solution

Instead of building infrastructure, you **declare what data you need**:

```rust
#[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,
}
```

Arete 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

```
┌──────────────────────────────────────────────────────────────┐
│  YOUR APP                                                    │
│  React hooks, TypeScript streams, or raw WebSocket           │
└──────────────────────────────────────────────────────────────┘
                              ▲
                              │ WebSocket (live updates)
                              ▼
┌──────────────────────────────────────────────────────────────┐
│  ARETE 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

### Stacks

A **Stack** is a deployed data pipeline that:

1. **Declares** one or more Solana programs it cares about — each with its own IDL
2. **Subscribes** to on-chain events across all of those programs
3. **Transforms** raw transaction data into structured entities
4. **Aggregates** values over time (sums, counts, etc.)
5. **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 Arete keeps it updated.

### 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

```rust
#[entity(name = "Token")]
pub struct Token {
    pub id: TokenId,       // Primary key section
    pub info: TokenInfo,   // Metadata section
    pub trading: Trading,  // Metrics section
}
```

### 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

**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

**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   |

```typescript
// List - all tokens as array
const { data: tokens } = stack.views.tokens.list.use();

// State - single token by key
const { 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

A **Stack SDK** is a generated package that tells the Arete 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

### Specification Time

1. Write stream definition using Rust macros
2. Build generates stack spec (`.arete/*.stack.json`)
3. Deploy with `a4 up`
4. Cloud compiles spec to bytecode

### Client

1. Connect to WebSocket
2. Subscribe to views
3. Receive live updates
4. React components re-render automatically

---

## Live Updates

Unlike traditional APIs where you poll for changes, Arete **pushes** updates to you.

### Update Types

| Type     | Meaning                       |
| -------- | ----------------------------- |
| `upsert` | Entity was created or updated |
| `delete` | Entity was removed            |

```typescript
for await (const update of a4.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

```
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

Arete provides end-to-end type safety:

1. **Spec types** - Rust ensures valid mappings at compile time
2. **Generated types** - SDK types match your entity definitions
3. **Runtime types** - Data arrives pre-shaped, no parsing needed

```typescript
// TypeScript knows token.mint is string, token.volume is bigint
const { data: token } = stack.views.tokens.state.use({ key });
console.log(token.mint); // string
console.log(token.volume); // bigint
```

---

## Next Steps

- [Quickstart](/using-stacks/quickstart) - Scaffold a working app in under 2 minutes
- [Connect to a Stack](/using-stacks/connect/) - Add Arete to your existing project
- [React SDK](/sdks/react/) - Build a complete React app
- [TypeScript SDK](/sdks/typescript/) - Framework-agnostic SDK
- [Rust SDK](/sdks/rust/) - Native Rust client
- [Building Stacks](/building-stacks/workflow) - Create custom data streams
- [CLI Commands](/cli/commands) - Deployment and management
