---
title: Surfpool SDK
description:
  Embed Surfpool in Rust and TypeScript tests. Start a local Surfnet, mutate
  account state, time travel, and deploy programs from code — without launching
  the CLI as a separate process.
---

The Surfpool SDK starts a full Surfnet runtime inside your test process. Use it
when you want a local Solana-compatible RPC endpoint, a pre-funded payer, and
direct state manipulation without launching `surfpool start` as a separate
process.

Both the Rust crate (`surfpool-sdk`) and the JS bindings (`@solana/surfpool`)
wrap the same runtime. The JS package ships pre-built native binaries through
napi-rs for macOS (Intel + Apple Silicon) and Linux x86-64, and also exposes a
[Solana Kit plugin](/docs/tools/surfpool/sdk/kit-plugin) entry point.

## Quickstart

Install the SDK, start a Surfnet, hit the RPC endpoint, then stop it. Parallel
tests share the same process safely because ports are allocated dynamically.

<CodeTabs storage="surfpool-lang">

```rust !! title="Rust"
use surfpool_sdk::{Signer, Surfnet};

#[tokio::test]
async fn starts_a_local_surfnet() {
    let surfnet = Surfnet::start().await.unwrap();

    let rpc = surfnet.rpc_client();
    let balance = rpc.get_balance(&surfnet.payer().pubkey()).unwrap();

    assert!(balance > 0);
    println!("rpc: {}", surfnet.rpc_url());
    println!("ws: {}", surfnet.ws_url());
}
```

```ts !! title="TypeScript"
import { after, test } from "node:test";
import assert from "node:assert/strict";
import { Surfnet } from "@solana/surfpool";

const surfnet = Surfnet.start();

after(() => {
  surfnet.stop();
});

test("starts a local surfnet", () => {
  assert.match(surfnet.rpcUrl, /^http:\/\/127\.0\.0\.1:\d+$/);
  assert.match(surfnet.wsUrl, /^ws:\/\/127\.0\.0\.1:\d+$/);
  assert.ok(surfnet.payer);
});
```

</CodeTabs>

## What's In The Box

<Cards>
  <Card
    title="Installation"
    href="/docs/tools/surfpool/sdk/installation"
    description="Cargo and npm setup, supported platforms, native binaries"
  />
  <Card
    title="Kit Plugin"
    href="/docs/tools/surfpool/sdk/kit-plugin"
    description="Embedded or attached Surfnet in a Kit client, pre-funded payer, typed cheatcodes RPC"
  />
  <Card
    title="Configuration"
    href="/docs/tools/surfpool/sdk/configuration"
    description="Builder options: remote RPC fallback, block production, slot timing, feature gates, custom payers"
  />
  <Card
    title="Cheatcodes"
    href="/docs/tools/surfpool/sdk/cheatcodes"
    description="Fund SOL/tokens, mutate accounts, reset upstream state, stream from mainnet"
  />
  <Card
    title="Time Travel"
    href="/docs/tools/surfpool/sdk/time-travel"
    description="Jump to an absolute slot, epoch, or Unix timestamp"
  />
  <Card
    title="Programs"
    href="/docs/tools/surfpool/sdk/programs"
    description="Anchor workspace auto-discovery, explicit .so + IDL deployment"
  />
  <Card
    title="Events"
    href="/docs/tools/surfpool/sdk/events"
    description="Drain runtime events for assertions and logging"
  />
  <Card
    title="Rust Reference"
    href="/docs/tools/surfpool/sdk/rust-reference"
    description="Complete surfpool-sdk crate API"
  />
  <Card
    title="JS Reference"
    href="/docs/tools/surfpool/sdk/js-reference"
    description="Complete @solana/surfpool TypeScript API"
  />
</Cards>

## How It Differs From `surfpool start`

The CLI runs a long-lived Surfnet you connect to from outside processes. The SDK
runs Surfnet _inside_ your test, which means:

- **No external port management** — every `Surfnet::start()` binds to a free
  port, so test suites can run in parallel without `--port` flags.
- **Synchronous teardown** — `stop()` returns when the runtime has actually
  released its ports.
- **Cheatcodes as typed methods** — the same surface exposed over JSON-RPC by
  `surfpool start` is available as native Rust methods and napi-rs bindings.
- **Direct event observation** — runtime events are exposed through an
  in-process channel (Rust) or a drain method (JS) without a WebSocket
  subscription.

## When To Use The SDK

Reach for the SDK when:

- You're writing **integration tests** for an Anchor program and want to assert
  on token balances after a sequence of cheatcoded setups.
- You need **parallel test workers** to each have an isolated Surfnet.
- You want to **mainnet-fork specific accounts** (`remoteRpcUrl` +
  `streamAccount`) inside a test.
- You need **deterministic clocks** by jumping the runtime to a fixed slot or
  timestamp before exercising vesting, lockup, or expiry logic.

<Callout type="info" title="When the CLI is the better fit">
  Use `surfpool start` instead when you want a Surfnet that survives across
  multiple processes — for example, when a CLI, browser wallet, and custom
  client scripts all need to share the same instance.
</Callout>
