# Overview

The Python SDK ships an async client alongside the synchronous one. Reach for it when your backend already runs on an async stack (FastAPI, aiohttp, or anything built on `asyncio`), or when you need to issue many Stream calls concurrently without tying up a thread per request. The async client mirrors the synchronous client: every network call becomes a coroutine you `await`.

## Initializing the async client

Import `AsyncStream` and construct it exactly like the synchronous `Stream` client:

```python
from getstream import AsyncStream

client = AsyncStream(api_key="your-api-key", api_secret="your-api-secret")
```

It also reads `STREAM_API_KEY` and `STREAM_API_SECRET` from environment variables, so you can construct it with no arguments:

```python
client = AsyncStream()
```

If you already have a synchronous `Stream` instance, convert it with `as_async()`:

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret").as_async()
```

## Making async calls

The API surface is identical to the synchronous client, except each network call is now awaited. Here is the getting-started flow rewritten for async:

```python
import asyncio

from getstream import AsyncStream
from getstream.models import UserRequest, ChannelInput, MessageRequest


async def main():
    async with AsyncStream(api_key="your-api-key", api_secret="your-api-secret") as client:
        # Upsert a user
        await client.upsert_users(UserRequest(id="john", name="John"))

        # Create or join a channel
        channel = client.chat.channel("messaging", "hello-world")
        await channel.get_or_create(data=ChannelInput(created_by_id="john"))

        # Send a message
        await channel.send_message(
            MessageRequest(text="Hello, Stream!", user_id="john")
        )


asyncio.run(main())
```

Note that `channel(...)` just builds a channel object locally, so it is not awaited. Token creation is also a local operation with no network call, so keep it synchronous:

```python
token = client.create_token(user_id="john")
```

## Cleaning up

The async client keeps an open connection pool, so close it when you are done. The `async with` block above does this for you: on exit it closes the pool along with any chat, video, or moderation sub-clients. If you manage the client's lifetime yourself, call `await client.aclose()` explicitly:

```python
client = AsyncStream(api_key="your-api-key", api_secret="your-api-secret")
try:
    await client.upsert_users(UserRequest(id="john", name="John"))
finally:
    await client.aclose()
```

Reuse a single client for the lifetime of your process rather than creating one per request. It maintains one shared connection pool across chat, video, and moderation. See [Connection Pooling](/chat/docs/python/connection-pooling/) for tuning the pool.

## Running calls concurrently

The payoff of async is concurrency. Use `asyncio.gather` to run independent calls at the same time instead of awaiting them one after another:

```python
await asyncio.gather(
    client.upsert_users(UserRequest(id="john", name="John")),
    client.upsert_users(UserRequest(id="jane", name="Jane")),
)
```

The client caps concurrent connections per host, so a large fan-out is queued through the pool rather than opening an unbounded number of sockets.

## Things to know

- Token-only clients cannot mint tokens or call admin endpoints. Pass `api_secret` for a server-side client that has full API access. See [Tokens & Authentication](/chat/docs/python/tokens-and-authentication/).
- The async client does not support Feeds. Accessing `client.feeds` raises `NotImplementedError`; use the synchronous `Stream` client for Feeds.


---

This page was last updated at 2026-07-08T16:04:55.126Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/python/async/](https://getstream.io/chat/docs/python/async/).