# Getting Started

The SDK binds your network and Ethereum clients once, then exposes ENS operations through focused
groups such as `name`, `records`, `registration`, and `indexer`.

Ensforge supports viem `2.49.0` and newer within version 2.

## Install

Install the SDK with Effect and viem.

:::code-group
```sh [pnpm]
pnpm add @ensforge/sdk effect@^4 viem
```

```sh [npm]
npm install @ensforge/sdk effect@^4 viem
```

```sh [yarn]
yarn add @ensforge/sdk effect@^4 viem
```

```sh [bun]
bun add @ensforge/sdk effect@^4 viem
```
:::

ensforge is ESM-only and includes its TypeScript declarations.

## Create an SDK

Create one viem `PublicClient`, pass it to `Ensforge`, and export the SDK from a shared module.

```ts [client.ts]
import { Ensforge } from "@ensforge/sdk";
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(process.env.MAINNET_RPC_URL),
});

export const sdk = new Ensforge({
  network: "mainnet",
  publicClient,
});
```

The viem client chain must match `network`. Use an authenticated RPC endpoint in production to avoid
public-provider rate limits.

## Read ENS

SDK methods return Promises, so they work in scripts, route handlers, server functions, and existing
async code without an Effect runtime at the call site.

```ts [profile.ts]
import { sdk } from "./client";

const [owner, address, avatar] = await Promise.all([
  sdk.name.getOwner({ name: "ens.eth" }),
  sdk.records.getAddress({ name: "ens.eth" }),
  sdk.records.getAvatar({ name: "ens.eth" }),
]);

console.log({ owner: owner.owner, address: address.address, avatar: avatar?.uri });
```

Names are normalized before contract interaction. Invalid names and failed reads reject with typed
ensforge errors.

## Use Effect

Every SDK method exposes its underlying Effect through `.effect`. Use it when you need typed error
channels, retries, interruption, concurrency, or tracing.

```ts [profile.ts]
import { Effect } from "effect";
import { sdk } from "./client";

const profile = Effect.all(
  {
    owner: sdk.name.getOwner.effect({ name: "ens.eth" }),
    address: sdk.records.getAddress.effect({ name: "ens.eth" }),
    avatar: sdk.records.getAvatar.effect({ name: "ens.eth" }),
  },
  { concurrency: "unbounded" },
);

const result = await Effect.runPromise(profile);
```

The Promise and Effect forms execute the same implementation and return the same success value.

## Add a wallet

Pass a viem `WalletClient` when this SDK will submit transactions.

```ts [client.ts]
import { Ensforge } from "@ensforge/sdk";
import { createPublicClient, createWalletClient, custom, http } from "viem";
import { mainnet } from "viem/chains";

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(process.env.MAINNET_RPC_URL),
});

const walletClient = createWalletClient({
  chain: mainnet,
  transport: custom(window.ethereum),
});

export const sdk = new Ensforge({
  network: "mainnet",
  publicClient,
  walletClient,
});
```

Write methods simulate by default before submitting the transaction.

```ts [update-profile.ts]
import { sdk } from "./client";

const receipt = await sdk.records.setText({
  name: "example.eth",
  key: "url",
  value: "https://example.com",
});
```

## Use an existing Wagmi config

Install `wagmi` and use the optional entrypoint when your application already owns a Wagmi config.
ensforge supports Wagmi 2.19 and 3.x.

```sh
pnpm add wagmi
```

:::code-group
```ts [client.ts]
import { createEnsforge } from "@ensforge/sdk/wagmi";
import { wagmiConfig } from "./wagmi";

export const sdk = createEnsforge({
  network: "mainnet",
  wagmiConfig,
});
```

```ts [wagmi.ts]
// [!include ~/snippets/wagmi/config.ts]
```
:::

Reads use Wagmi's public client. Writes resolve the currently connected wallet when they execute,
so account and connector changes do not require recreating the SDK.

## Import types

Shared configuration types are exported from `@ensforge/sdk`. Action-specific types use focused
group entrypoints to keep editor work small.

```ts
import type { CreateConfigParameters } from "@ensforge/sdk";
import type { GetOwnerParameters } from "@ensforge/sdk/name";
import type { SetTextParameters } from "@ensforge/sdk/records";
```

Calling methods through `sdk` remains fully inferred; import these types only when annotating your
own boundaries.

## Next steps

* Browse the [`Ensforge` client](/sdk/api/ensforge) and its grouped methods.
* Learn how to combine compatible reads in [Batching](/sdk/guides/batching).
* Handle typed failures in [Error Handling](/sdk/guides/error-handling).
* Build a UI with [ensforge React](/react/getting-started).
