# Set up a tRPC Client

> 

### 1. Install the tRPC Client library

Use your preferred package manager to install the `@trpc/client` library, and also install `@trpc/server` which contains some required types.

```package-install
@trpc/server @trpc/client
```

### 2. Import your App Router

Import your `AppRouter` type into the client application. This type holds the shape of your entire API.

```ts title="utils/trpc.ts"
import type { AppRouter } from '../server/router';
```

> [!TIP]
> By using `import type` you ensure that the reference will be stripped at compile-time, meaning you don't inadvertently import server-side code into your client. For more information, [see the Typescript docs](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export).


### 3. Initialize the tRPC client

Create a tRPC client with the `createTRPCClient` method, and add a `links` array with a [terminating link](https://trpc.io/docs/client/links.md#the-terminating-link) pointing at your API. To learn more about tRPC links, [click here](https://trpc.io/docs/client/links.md).

```ts title="client.ts"
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';

const client = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000/trpc',

      // You can pass any HTTP headers you wish here
      async headers() {
        return {
          authorization: getAuthCookie(),
        };
      },
    }),
  ],
});
```

### 4. Use the tRPC Client

Under the hood this creates a typed [JavaScript Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) which allows you to interact with your tRPC API in a fully type-safe way:

```ts title="client.ts"
const bilbo = await client.getUser.query('id_bilbo');
// => { id: 'id_bilbo', name: 'Bilbo' };

const frodo = await client.createUser.mutate({ name: 'Frodo' });
// => { id: 'id_frodo', name: 'Frodo' };
```

### 5. Use subscriptions

Given a [subscription procedure](https://trpc.io/docs/server/subscriptions.md) and a link that supports subscriptions, such as [`httpSubscriptionLink`](https://trpc.io/docs/client/links/httpSubscriptionLink.md) or [`wsLink`](https://trpc.io/docs/client/links/wsLink.md), `.subscribe()` starts the subscription. Either pass callbacks, or leave them out and iterate the result with `for await`:

```ts title="client.ts"
// with callbacks
const sub = client.onUserAdd.subscribe(undefined, {
  onData(user) {
    console.log(user);
  },
});
// stop listening
sub.unsubscribe();

// or with `for await`, without callbacks
const ac = new AbortController();
const users = client.onUserAdd.subscribe(undefined, { signal: ac.signal });
for await (const user of users) {
  // const user: {
  //     name: string;
  // }
  console.log(user);
}
// `ac.abort()` stops it from outside the loop
```

When you iterate a subscription:

- A subscription is either iterated or uses callbacks. Iterating one that was started with callbacks throws, and is a type error.
- Without callbacks, `.subscribe()` returns an async iterator with no `unsubscribe()`, like Node's `events.on()`. Stop it from inside the loop with `break` or `return`, or from outside by aborting the `signal` you passed.
- Data is queued from when `.subscribe()` is called until the loop reads it. The queue has no size limit. A subscription can be iterated once: a second `for await` over it throws. To consume it twice, call `.subscribe()` twice.
- A subscription you never loop over or abort keeps running, so pass a `signal`.
- If you called `unsubscribe()` on a subscription started without callbacks, pass a `signal` and `abort()` it instead.
- Leaving the loop with `break`, `return` or a thrown error unsubscribes and drops the queued data.
- Aborting the `signal` unsubscribes, and the loop yields the data already queued before it ends.
- An error from the subscription is thrown from the loop as a `TRPCClientError`, after the data received before it.

You're all set!

## Common mistakes

- **Leaving out the `AppRouter` type parameter.** `createTRPCClient({ links })` without `<AppRouter>` compiles, but none of your procedures are typed. If the `AppRouter` import doesn't resolve (often a monorepo path or `tsconfig` issue), fix the import rather than reaching for `createTRPCClient<any>`.
- **Importing the router value instead of its type.** `import { appRouter } from '../server/router'` pulls your server code into the client bundle. Export `type AppRouter = typeof appRouter` from the server and import it with `import type`.
- **Passing `transformer` to `createTRPCClient`.** The transformer belongs on each terminating link (`httpBatchLink`, `httpLink`, `wsLink`, ...), and TypeScript rejects it on the client itself. See [Data Transformers](https://trpc.io/docs/server/data-transformers.md).
- **Using `createTRPCProxyClient`.** It's the v10 name, kept as a deprecated alias of `createTRPCClient`.
- **Calling procedures like REST endpoints.** Procedures are addressed by their dot-separated path, for example `GET /trpc/post.byId?input=...`, not `/trpc/post/1`. Call them through the client, or see the [HTTP RPC Specification](https://trpc.io/docs/rpc.md) for the wire format.
- **A JSON parse error like `Unexpected token '<'`.** The request reached something that answered with an HTML page, usually a 404, so the link's `url` doesn't match where your adapter serves tRPC (check the `/trpc` prefix).
