> ## Documentation Index
> Fetch the complete documentation index at: https://upstash.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Connecting

> Build a bucket client from the bucket token, on any platform, and reach storage through an S3 client.

This page covers creating the bucket client from its token, how it retries, what it sends as telemetry, and reaching storage through an S3 client.

```ts TypeScript theme={"system"}
import { Bucket } from "@upstash/blob"

export const bucket = Bucket.fromEnv() // reads UPSTASH_BLOB_TOKEN
```

```python Python theme={"system"}
from upstash_blob import Bucket

bucket = Bucket.from_env()  # reads UPSTASH_BLOB_TOKEN
```

```go Go theme={"system"}
import blob "github.com/upstash/blob-go"

bucket, err := blob.NewBucketFromEnv() // reads UPSTASH_BLOB_TOKEN
```

Client options and their types: [TypeScript](https://upstash.com/docs/blob/sdks/ts/overview#the-bucket-client), [Python](https://upstash.com/docs/blob/sdks/py/overview#the-bucket-client), [Go](https://upstash.com/docs/blob/sdks/go/overview#the-bucket-client).

Create a bucket in the [Upstash Console](https://console.upstash.com) and put its token in your environment:

```bash .env theme={"system"}
UPSTASH_BLOB_TOKEN=...
```

Every SDK reads `UPSTASH_BLOB_TOKEN` by default and also takes a token directly, for a token under another variable or a platform without environment variables, such as Cloudflare Workers.

The token is a bearer secret. Anything holding it can read and write the whole bucket. Keep it server side, never in `NEXT_PUBLIC_`, `VITE_`, or any other variable your bundler inlines into client code.

***

## Options

| Option | Default | Description |
| - | - | - |
| Token | `UPSTASH_BLOB_TOKEN` | The bucket token. |
| Cache | `'1h'` | The default `Cache-Control` for every object this client stores. A per-call cache overrides it. See [Caching](https://upstash.com/docs/blob/bucket/caching). |
| Telemetry | on | See [Telemetry](#telemetry). |
| Retry | 2 retries | Off, or a retry count and backoff. See [Retries](#retries). |

Constructing a client per request is fine. Credentials are cached per token, so two clients built from the same token share one.

### Public or private

Whether the bucket is public or private is a console setting, not an option: the SDK learns it from the backend on the first request. See [Private buckets](https://upstash.com/docs/blob/bucket/reading#private-buckets).

***

## Retries

```ts TypeScript theme={"system"}
new Bucket({ token, retry: false }) // every request once
new Bucket({ token, retry: { retries: 5, backoff: (n) => n * 500 } })
```

```python Python theme={"system"}
Bucket(token, retry=False)  # every request once
Bucket(token, retry={"retries": 5, "backoff": lambda n: n * 500})
```

```go Go theme={"system"}
// every request once
blob.NewBucketWith(blob.Options{
	Token: token,
	Retry: blob.RetryConfig{Disabled: true},
})

blob.NewBucketWith(blob.Options{
	Token: token,
	Retry: blob.RetryConfig{
		Retries: 5,
		Backoff: func(n int) time.Duration {
			return time.Duration(n) * 500 * time.Millisecond
		},
	},
})
```

A request that fails with a 5xx, a 429 or a dropped connection is sent again if it can be: reads, deletes, copies, multipart parts and signing calls. A `put` that goes up as one PUT with a streamed body is sent once, since a stream cannot be read twice. In TypeScript every body is streamed; in Python a body held in memory is retried: `bytes`, a `str`, or one buffered under `max_size`. In Go a body that can be read again is retried: a `*bytes.Reader`, a `*strings.Reader`, a regular file, or one buffered under `MaxSize`; see [Bodies](https://upstash.com/docs/blob/sdks/go/bucket#bodies). The POSTs that create and complete a multipart upload and a batch delete are sent once. When the credential service asks the SDK to wait, it waits up to 10 seconds and asks again, three times.

| Setting | Default | Description |
| - | - | - |
| Retries | `2`, and `3` for credentials | Retries after the first attempt, for every request this client makes. |
| Backoff | full jitter, doubling from 200 ms, capped at 4 s; 2 s for credentials | Milliseconds before each retry. A `Retry-After` from the service wins over it. |

Clients built from the same token share one credential cache, so a credential fetch already in progress keeps the retry setting of the client that started it. An expired temporary credential is not a failure: the SDK fetches a new one and sends the request once more, even with retries off, unless its body was a stream. Browser uploads retry on their own budget; see [Retries](https://upstash.com/docs/blob/uploads/large-files#retries).

***

## Telemetry

The SDK sends its version, runtime and platform as headers on credential and signing requests to Upstash. Turn it off with `UPSTASH_DISABLE_TELEMETRY` in the environment, set to anything but an empty string, `false`, `0`, `no` or `off`, or with the telemetry option on the client.

***

## Using an S3 client

```ts TypeScript theme={"system"}
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"

const { endpoint, region, bucket: name, credentials } = bucket.s3()
const s3 = new S3Client({ endpoint, region, credentials })

await s3.send(
  new GetObjectCommand({ Bucket: name, Key: "reports/q3.pdf", Range: "bytes=0-1023" }),
)
```

```python Python theme={"system"}
import boto3

cfg = bucket.s3()
s3 = boto3.client("s3", **cfg.client_kwargs())

s3.get_object(Bucket=cfg.bucket, Key="reports/q3.pdf", Range="bytes=0-1023")
```

```go Go theme={"system"}
cfg, err := bucket.S3(ctx)
if err != nil {
	return err
}
client := s3.New(s3.Options{
	Region:       cfg.Region,
	BaseEndpoint: aws.String(cfg.Endpoint),
	Credentials:  credentials, // refreshed from bucket.S3, see the Go SDK page
})

client.GetObject(ctx, &s3.GetObjectInput{
	Bucket: aws.String(cfg.Bucket),
	Key:    aws.String("reports/q3.pdf"),
	Range:  aws.String("bytes=0-1023"),
})
```

Buckets are backed by Cloudflare R2 and are S3-compatible. The client's `s3()` returns a config for an S3 client, for anything the SDK does not wrap: byte ranges, conditional GETs, delimiters and common prefixes, object tagging. The credentials in it are short-lived; see [Minting temporary credentials](https://upstash.com/docs/blob/reference/signing#minting-temporary-credentials).

Wiring it into an S3 client: [TypeScript](https://upstash.com/docs/blob/sdks/ts/overview#using-an-s3-client), [Python](https://upstash.com/docs/blob/sdks/py/overview#using-an-s3-client), [Go](https://upstash.com/docs/blob/sdks/go/overview#using-an-s3-client).

> [!WARNING]
>
> Do not presign URLs with this client. A presigned URL carries the credential, which reads and writes the whole bucket until it expires. Use [signed read URLs](https://upstash.com/docs/blob/bucket/reading#signed-read-urls) and [signed upload URLs](https://upstash.com/docs/blob/bucket/writing#signed-upload-urls), which Upstash signs for one object; see [Who signs a URL](https://upstash.com/docs/blob/reference/signing#who-signs-a-url).

***

## Next steps

> [card] [Writing](https://upstash.com/docs/blob/bucket/writing)
>
> `put`, metadata, conditional writes and multipart from the server.

> [card] [Reading](https://upstash.com/docs/blob/bucket/reading)
>
> `get`, `info`, `exists`, `list` and signed read URLs.


## Related topics

- [Connecting with Read-Only Access](https://upstash.com/docs/redis/troubleshooting/readonly_connection.md)
- [effect-mq with Upstash Redis](https://upstash.com/docs/redis/integrations/effect-mq.md)
- [Upstash Redis with DigitalOcean](https://upstash.com/docs/redis/quickstarts/digitalocean.md)
- [TypeScript SDK](https://upstash.com/docs/blob/sdks/ts/overview.md)
- [Datadog - Upstash QStash Integration](https://upstash.com/docs/qstash/integrations/datadog.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.