> ## Documentation index
> Fetch the complete documentation index at: https://upstash.com/docs/llms.txt
> Ask it with GET https://upstash.com/docs/ask?q=<keywords or question>. Short keywords rank best.
> Use these to discover all available pages before exploring further.
> Feature requests: https://upstash.com/docs/common/help/feature-requests.md lists what users asked for and how to vote for a request or add one.
> Page rating: `GET https://upstash.com/docs/feedback?path=/docs/blob/bucket/connecting&helpful=true` (or `false`) records whether this page helped. An optional `comment` (URL-encoded, at most 500 characters) says what was missing or wrong. It is anonymous and needs no key. Comments hold no code, secrets or personal data.

# 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.

<CodeGroup>
```ts TypeScript
import { Bucket } from "@upstash/blob"

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

```python Python
from upstash_blob import Bucket

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

```go Go
import blob "github.com/upstash/blob-go"

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

Client options and their types: [TypeScript](/blob/sdks/ts/overview#the-bucket-client), [Python](/blob/sdks/py/overview#the-bucket-client), [Go](/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
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](/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](/blob/bucket/reading#private-buckets).

---

## Retries

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

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

```go Go
// 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
		},
	},
})
```
</CodeGroup>

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](/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](/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

<CodeGroup>
```ts TypeScript
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
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
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"),
})
```
</CodeGroup>

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](/blob/reference/signing#minting-temporary-credentials).

Wiring it into an S3 client: [TypeScript](/blob/sdks/ts/overview#using-an-s3-client), [Python](/blob/sdks/py/overview#using-an-s3-client), [Go](/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](/blob/bucket/reading#signed-read-urls) and [signed upload URLs](/blob/bucket/writing#signed-upload-urls), which Upstash signs for one object; see [Who signs a URL](/blob/reference/signing#who-signs-a-url).
</Warning>

---

## Next steps

<CardGroup cols={2}>
  <Card title="Writing" href="/blob/bucket/writing">
    `put`, metadata, conditional writes and multipart from the server.
  </Card>

  <Card title="Reading" href="/blob/bucket/reading">
    `get`, `info`, `exists`, `list` and signed read URLs.
  </Card>
</CardGroup>
