# Links

> A client's chain of links, the built-in ones, and the order they go in.

A client's `links` is a chain: each link gets the operation and the rest of the chain. The links in the middle route, retry, share or log operations; the last one, the terminating link, carries them to a server or runs them in process.

```ts
import {
  createTrpcClient,
  dedupeLink,
  httpLink,
  loggerLink,
  retryLink,
  routerType,
} from '@trpc12/trpc/client';

const client = createTrpcClient({
  router: routerType<AppRouter>(),
  links: [
    loggerLink({ enabled: () => process.env.NODE_ENV === 'development' }),
    dedupeLink(),
    retryLink(),
    httpLink({ url: 'http://localhost:3000/trpc', batch: true }),
  ],
});
```

An operation goes through the links in order and its results come back the other way. Here the logger sees each call once, and identical queries are shared before the retries, so a retried query is still one request for every caller.

## Terminating links

| Link                            | Carries calls                                                                  |
| ------------------------------- | ------------------------------------------------------------------------------ |
| [`httpLink`](https://v12.trpc.io/docs/client/links/http.md)   | Over HTTP: queries as `GET`, mutations as `POST`, subscriptions as SSE         |
| [`wsLink`](https://v12.trpc.io/docs/client/links/ws.md)       | Over one WebSocket                                                             |
| [`localLink`](https://v12.trpc.io/docs/client/links/local.md) | To a router in the same process                                                |
| `experimental_socketLink`       | Over a raw TCP, TLS or Unix socket ([Raw sockets](https://v12.trpc.io/docs/adapters/sockets.md))     |
| `experimental_messagePortLink`  | To a worker or a `MessagePort` ([Message ports](https://v12.trpc.io/docs/adapters/message-ports.md)) |
| `openApiLink`                   | To each procedure's REST route ([Calling REST](https://v12.trpc.io/docs/openapi/client.md))          |

## Links in the middle

| Link                                | Does                                                                                     |
| ----------------------------------- | ---------------------------------------------------------------------------------------- |
| [`splitLink`](https://v12.trpc.io/docs/client/links/split.md)     | Picks one of two chains per call                                                         |
| [`switchLink`](https://v12.trpc.io/docs/client/links/switch.md)   | Picks one of several named chains, and a call can force one                              |
| [`retryLink`](https://v12.trpc.io/docs/client/links/retry.md)     | Retries failed calls                                                                     |
| [`dedupeLink`](https://v12.trpc.io/docs/client/links/dedupe.md)   | Shares identical queries in flight                                                       |
| [`loggerLink`](https://v12.trpc.io/docs/client/links/logger.md)   | Logs every operation, its results and its errors                                         |
| [`validationLink`](https://v12.trpc.io/docs/client/validation.md) | Checks inputs and results against a contract                                             |
| `experimental_durableLink`          | Retries lost responses with the same call id ([Durable calls](https://v12.trpc.io/docs/middleware/durable.md)) |

## Call options

A link declares the call options it reads (`dedupe` for `dedupeLink`, a `switchLink`'s name), and a client made with `router:` types them on every call, next to the built-in `signal`, `headers`, `init`, `batch` and `reconnect` ([The client](https://v12.trpc.io/docs/client/overview.md#call-options)).

`link(({ op, next }) => stream)` writes a link of your own, with the call options it reads, the errors it fails with and what it needs from the links after it ([Custom links](https://v12.trpc.io/docs/client/custom-links.md)).
