# Connection Pooling

Every backend SDK ships with HTTP connection pooling configured by default. The SDK emits one INFO-level log on client construction listing the effective values so you can verify your configuration.

## Defaults

| Setting                  | Default   | What it does                                                                     |
| ------------------------ | --------- | -------------------------------------------------------------------------------- |
| Max connections per host | `5`       | Upper bound on concurrent TCP connections to a single host.                      |
| Idle timeout             | `55 s`    | Closes a connection that has been idle for this duration.                        |
| Connect timeout          | `10 s`    | Caps the TCP + TLS handshake.                                                    |
| Request timeout          | `30 s`    | Default per-call deadline from request send to full response. Override per call. |
| Keep-alive               | always on | HTTP persistent connection reuse. Not user-tunable.                              |

## Tune the knobs

Pass the four knobs at client construction.

<Tabs>

```go label="Go"
client, err := stream.NewClient(apiKey, apiSecret,
    stream.WithMaxConnsPerHost(20),
    stream.WithIdleTimeout(55*time.Second),
    stream.WithConnectTimeout(5*time.Second),
    stream.WithRequestTimeout(20*time.Second),
)
```

```python label="Python"
client = Stream(
    api_key=api_key,
    api_secret=api_secret,
    max_conns_per_host=20,
    idle_timeout=55.0,
    connect_timeout=5.0,
    request_timeout=20.0,
)
```

```java label="Java"
StreamClientOptions opts = new StreamClientOptions()
    .setMaxConnsPerHost(20)
    .setIdleTimeout(Duration.ofSeconds(55))
    .setConnectTimeout(Duration.ofSeconds(5))
    .setRequestTimeout(Duration.ofSeconds(20));
StreamSDKClient client = new StreamSDKClient(apiKey, apiSecret, opts);
```

```csharp label=".NET"
var client = new StreamClient(new StreamOptions
{
    ApiKey = apiKey,
    ApiSecret = apiSecret,
    MaxConnsPerHost = 20,
    IdleTimeout = TimeSpan.FromSeconds(55),
    ConnectTimeout = TimeSpan.FromSeconds(5),
    RequestTimeout = TimeSpan.FromSeconds(20),
});
```

```ruby label="Ruby"
client = GetStreamRuby::Client.new(
  api_key: api_key,
  api_secret: api_secret,
  max_conns_per_host: 20,
  idle_timeout: 55,
  connect_timeout: 5,
  request_timeout: 20,
)
```

```php label="PHP"
$client = ClientBuilder::create()
    ->apiKey($apiKey)
    ->apiSecret($apiSecret)
    ->maxConnsPerHost(20)
    ->idleTimeout(55)
    ->connectTimeout(5)
    ->requestTimeout(20)
    ->build();
```

</Tabs>

## Per-call request timeout

Override the request timeout for a single call without rebuilding the client.

<Tabs>

```go label="Go"
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.Common().GetApp(ctx)
```

```python label="Python"
import httpx
response = client.get_app(timeout=httpx.Timeout(5.0))
```

```java label="Java"
request.callTimeout(Duration.ofSeconds(5)).execute();
```

```csharp label=".NET"
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var app = await client.GetAppAsync(cts.Token);
```

```ruby label="Ruby"
client.make_request(:get, "/api/v2/app", request_timeout: 5)
```

```php label="PHP"
$client->getHttpClient()->request("GET", $url, $headers, null, ["timeout" => 5]);
```

</Tabs>

## Bring your own HTTP client

When you pass a pre-built HTTP client, the SDK uses it as-is and applies none of the four knobs above. You own all transport behavior, including timeouts, retries, and response decompression.

<Tabs>

```go label="Go"
client, err := stream.NewClient(apiKey, apiSecret,
    stream.WithHTTPClient(&http.Client{Timeout: 10 * time.Second}),
)
```

```python label="Python"
import httpx
client = Stream(api_key=api_key, api_secret=api_secret, http_client=httpx.Client(timeout=10.0))
```

```java label="Java"
StreamClientOptions opts = new StreamClientOptions().setHttpClient(myOkHttpClient);
StreamSDKClient client = new StreamSDKClient(apiKey, apiSecret, opts);
```

```csharp label=".NET"
var client = new StreamClient(new StreamOptions
{
    ApiKey = apiKey,
    ApiSecret = apiSecret,
    HttpClient = myHttpClient,
});
```

```ruby label="Ruby"
client = GetStreamRuby::Client.new(
  api_key: api_key,
  api_secret: api_secret,
  http_client: my_faraday_connection,
)
```

```php label="PHP"
$client = ClientBuilder::create()
    ->apiKey($apiKey)
    ->apiSecret($apiSecret)
    ->httpClient($myGuzzleClient)
    ->build();
```

</Tabs>

## SDK-specific notes

- **PHP**: `maxConnsPerHost` and `idleTimeout` are enforced via libcurl's persistent multi-handle pool (`CURLMOPT_MAX_HOST_CONNECTIONS` and `CURLOPT_MAXLIFETIME_CONN`). They take effect only when the SDK client is reused across requests within a single PHP process: long-running runtimes such as Swoole, RoadRunner, ReactPHP, and CLI daemons. Instantiate the SDK client once and reuse it. Under PHP-FPM (and one-shot CLI scripts) the PHP process exits at the end of each request, so there is no cross-request pool to size; the per-call request and connect timeouts still apply. `idleTimeout` requires libcurl 7.80.0 (Nov 2021) or later.
- **Ruby**: pooling relies on the `net_http_persistent` Faraday adapter. If a custom `faraday_adapter:` you pass cannot be configured, the SDK logs a warning and falls back to Faraday's default (non-pooling) adapter; the INFO log on construction reports the effective adapter.
- **Java**: the environment variables `STREAM_API_TIMEOUT` and `STREAM_API_CONNECTION_MAX_AGE` (and their system-property equivalents `io.getstream.timeout` and `io.getstream.connection.maxAge`) still take effect and are folded into the default options.
- **.NET**: on the escape-hatch path the SDK does not configure gzip decompression on your handler. Enable `AutomaticDecompression = DecompressionMethods.GZip` on your own `SocketsHttpHandler` if you need it.


---

This page was last updated at 2026-05-28T10:34:35.666Z.

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