# Stream Send (/sdks/nodejs/how-to/events-store/stream-send)



## Overview [#overview]

**Stream send** covers publishing a batch of persistent events over one long-lived connection instead of opening a new request for each message. A single-shot publish call is fine for one-off writes, but if you're bulk-loading history, replicating a firehose of records, or backfilling an Events Store channel, paying gRPC connection overhead once instead of per-message turns network latency into your throughput ceiling instead of an app-level bottleneck.

`createEventStoreStream()` opens a persistent bidirectional gRPC stream you reuse for every message. Each `await stream.send(...)` still confirms storage before resolving — events are persisted in sequence and available for replay immediately — and `stream.onError()` catches any mid-batch stream failure instead of letting it fail silently. &#x2A;*Gotchas:** because each send awaits its own confirmation, this pattern is latency-bound per call — true concurrent throughput needs multiple in-flight sends, not just a shared connection; calling `stream.close()` before outstanding sends resolve can cut off their confirmations; and for occasional publishing, opening and tearing down a stream is pure overhead — publish a single event store message directly instead.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Node.js SDK installed (`npm install kubemq-js`)

## Code [#code]

```typescript title="stream-send.ts"
import { KubeMQClient, createEventStoreMessage } from 'kubemq-js';

async function main() {
  const client = await KubeMQClient.create({
    address: 'localhost:50000',
    clientId: 'js-events-store-stream-send-client',
  });

  try {
    const stream = client.createEventStoreStream();
    stream.onError((err) => {
      console.error('Stream error:', err.message);
    });

    for (let i = 1; i <= 5; i++) {
      await stream.send(
        createEventStoreMessage({
          channel: 'js-events-store.stream-send',
          body: `persisted #${i}`,
        }),
      );
      console.log('Persisted event', i);
    }

    stream.close();
    console.log('Event store stream closed');
  } finally {
    await client.close();
  }
}

main().catch(console.error);

```

## How It Works [#how-it-works]

* `createEventStoreStream()` opens a persistent bidirectional gRPC stream optimized for high-throughput persisted event ingestion.
* Each `await stream.send()` writes one event to the stream and waits for the flush — the events are persisted in sequence and available for replay immediately.
* `stream.onError()` is registered before the first send so any mid-batch stream failure is caught rather than silently lost.
* `stream.close()` half-closes the write side of the stream; `client.close()` then tears down the underlying gRPC channel cleanly.

## Related [#related]

* [Pattern overview](/learn/events-store/getting-started)
* [Node.js SDK Reference](/sdks/nodejs/reference)
* [Persistent Pub/Sub](/sdks/nodejs/tutorials/persistent-pubsub)
* [Cancel Subscription](/sdks/nodejs/how-to/events-store/cancel-subscription)
