# Streaming

> Return async generators, Effect streams and nested promises; validate each item with stream().

A query or mutation can return an async generator or an Effect `Stream`, and the client gets an `AsyncIterable`. Outputs can also hold promises and async iterables at any depth: the rest of the output arrives first, and each deferred value streams as it settles.

```ts
const countdown = t.procedure.query(async function* () {
  for (let i = 3; i > 0; i--) {
    yield i;
  }
  return 'liftoff';
});

const page = t.procedure.query(() => ({
  title: 'Post',
  comments: Promise.resolve(['First!']),
}));
```

Over HTTP, `httpLink` reads such outputs as JSONL (or binary frames, [Files](https://v12.trpc.io/docs/server/files.md)); `wsLink`, `experimental_messagePortLink` and `localLink` carry them as they are. Every [serializer](https://v12.trpc.io/docs/server/serializers.md) streams deferred values.

## Validating items

To validate each item, wrap the item schema in `stream()`; a second schema validates the generator's return value, which the client gets as the iterator's final value:

```ts
import { stream } from '@trpc12/trpc/server';

const chat = t.procedure
  .output(stream(Token, Summary))
  .mutation(async function* () {
    yield { text: 'He' };
    yield { text: 'llo' };
    return { tokens: 2 };
  });
```

```ts
const it = await client.chat.mutate(); // AsyncIterable<Token, Summary>
```

A plain `.output(Item)` on a streaming resolver is a type error that points to `stream()`. An invalid item fails the stream with `INTERNAL_SERVER_ERROR` after the items before it have been delivered. Streams nested inside an object output aren't validated.

Over HTTP the server reads a stream only as fast as the client reads the response: a generator waits at its `yield` while the client is behind, and its `finally` runs when the client leaves. WebSocket links don't wait yet; there, a slow client buffers on the server.

## Streams and subscriptions

A streamed query or mutation is one call whose result arrives in pieces; the client consumes it once. A [subscription](https://v12.trpc.io/docs/subscriptions/overview.md) is a stream of events the client follows, with `tracked()` ids to resume after a reconnect. For progress of long jobs in TanStack Query, see [Streamed mutations](https://v12.trpc.io/docs/integrations/tanstack-query.md#streamed-mutations).
