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

# Blob Storage: S3-Compatible Object Storage with CDN

> S3-compatible object storage with a global CDN, private files, temporary and share links, and no transfer fees. Included in every Square Cloud plan.

export const BlobFlow = ({labels: l}) => {
  const dots = {
    app: "#3b82f6",
    browser: "#8b5cf6",
    s3: "#f59e0b",
    pub: "#06b6d4",
    tmp: "#10b981",
    share: "#ec4899"
  };
  const inputs = ["app", "browser", "s3"];
  const outputs = ["pub", "tmp", "share"];
  const box = (k, x, y, [w, h, ft, fs]) => <g key={`${k}-${x}-${y}`}>
      <rect className="d-box" x={x} y={y} width={w} height={h} rx="10" strokeWidth="1" />
      <circle cx={x + 20} cy={y + h / 2 - 9} r="4.5" fill={dots[k]} />
      <text className="d-title" x={x + 32} y={y + h / 2 - 4} fontSize={ft}>{l[k]}</text>
      <text className="d-text" x={x + 20} y={y + h / 2 + 16} fontSize={fs}>{l[k + "Sub"]}</text>
    </g>;
  const marker = id => <defs>
      <marker id={id} viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
        <path d="M0 0 L10 5 L0 10 z" fill="#64748b" />
      </marker>
    </defs>;
  const line = id => d => <path key={d} className="d-line" d={d} fill="none" strokeWidth="1.5" strokeDasharray="4 4" markerEnd={`url(#${id})`} />;
  const cloud = (x, y) => <g>
      <rect x={x} y={y} width="44" height="44" rx="10" fill="#1d4ed8" />
      <path transform={`translate(${x - 358} ${y - 106})`} d="M389.5 136H374.5a8 8 0 1 1 7.6-10.4h2.2a5.2 5.2 0 0 1 5.2 10.4z" fill="none" stroke="#fff" strokeWidth="1.8" strokeLinejoin="round" />
    </g>;
  const chips = (x, y) => <g>
      <rect className="d-chip" x={x} y={y} width="52" height="24" rx="6" />
      <text className="d-chip-text" x={x + 26} y={y + 16} fontSize="12" textAnchor="middle">pub/</text>
      <rect className="d-chip" x={x + 60} y={y} width="52" height="24" rx="6" />
      <text className="d-chip-text" x={x + 86} y={y + 16} fontSize="12" textAnchor="middle">prv/</text>
    </g>;
  const W = [210, 64, 16, 14];
  const T = [319, 56, 15, 13];
  return <div className="sc-diagram">
      <svg className="d-wide" viewBox="0 0 720 280" role="img" aria-label={l.alt} fontFamily="inherit">
        {marker("sc-arrow")}
        {["M215 42 C 245 42, 245 120, 275 120", "M215 140 L 275 140", "M215 238 C 245 238, 245 160, 275 160", "M445 120 C 475 120, 475 42, 505 42", "M445 140 L 505 140", "M445 160 C 475 160, 475 238, 505 238"].map(line("sc-arrow"))}
        {inputs.map((k, i) => box(k, 5, 10 + i * 98, W))}
        {outputs.map((k, i) => box(k, 505, 10 + i * 98, W))}
        <rect className="d-core" x="275" y="72" width="170" height="136" rx="12" strokeWidth="1.5" />
        {cloud(338, 86)}
        <text className="d-title" x="360" y="152" fontSize="16" textAnchor="middle">{l.core}</text>
        {chips(304, 166)}
      </svg>

      <svg className="d-tall" viewBox="0 0 320 520" role="img" aria-label={l.alt} fontFamily="inherit">
        {marker("sc-arrow-v")}
        {["M160 186 L 160 216", "M160 298 L 160 328"].map(line("sc-arrow-v"))}
        {inputs.map((k, i) => box(k, 0.5, 0.5 + i * 64, T))}
        <rect className="d-core" x="0.5" y="222" width="319" height="70" rx="12" strokeWidth="1.5" />
        {cloud(14, 235)}
        <text className="d-title" x="70" y="262" fontSize="16">{l.core}</text>
        {chips(194, 245)}
        {outputs.map((k, i) => box(k, 0.5, 334.5 + i * 64, T))}
      </svg>
    </div>;
};

<Frame>
  <img src="https://squarecloud.app/banners/en/blob.png" alt="Square Cloud Blob Storage service overview" style={{ borderRadius: "0.2rem" }} />
</Frame>

## Why choose Square Cloud Blob Storage?

As the **largest bot hosting platform in Latin America**, trusted by **80 of the 100 largest Brazilian Discord servers**, we built Blob Storage to solve a problem our own community kept hitting: **Discord's CDN was never meant to be a storage backend**, and links break, expire or get rate-limited. Blob Storage replaces that with an object store designed for durability.

The design is simple on purpose: **S3-compatible object storage is the source of truth** for your files, and a **global CDN** delivers them from the edge. You get the **11-nines durability** of an S3 design with the read latency of a global cache, and every plan includes **generous storage**.

## Key features

<CardGroup cols={2}>
  <Card title="No transfer fees" icon="money-bill">
    **Zero ingress and egress fees.** Upload and serve as much as you need: you pay for storage, never for bandwidth.
  </Card>

  <Card title="Global CDN" icon="globe">
    Public files are served from a **global CDN**, at the edge, close to your users wherever they are.
  </Card>

  <Card title="Private files" icon="lock">
    Store files **without a public URL** and hand them out through [temporary links or share links](/en/blob-reference/links-and-sharing). Switch any file between public and private at any time.
  </Card>

  <Card title="Share links" icon="share-nodes">
    Links that **expire**, can be **revoked**, cap the **number of downloads** and, on Pro and Enterprise, ask for a **password**.
  </Card>

  <Card title="S3-compatible" icon="bucket">
    Use **aws-cli, boto3, rclone** or any AWS SDK through the [S3 gateway](/en/blob-reference/s3-compatibility), with credentials derived from your API key.
  </Card>

  <Card title="Browser uploads" icon="upload">
    Your server mints an [upload token](/en/blob-reference/endpoint/upload-tokens) and the **browser uploads directly**, without ever seeing your API key.
  </Card>

  <Card title="Rules per prefix" icon="sliders">
    Set defaults (visibility, expiry, cache), limits (size, file types) and **automatic deletion after N days** for everything under a prefix with [account settings](/en/blob-reference/endpoint/settings-put).
  </Card>

  <Card title="Server-side operations" icon="arrows-rotate">
    [Copy, move and rename](/en/blob-reference/endpoint/copy) files without downloading them, and [change headers](/en/blob-reference/endpoint/update) (cache, disposition, metadata) in place.
  </Card>
</CardGroup>

## How it works

Files come in through the REST API, the browser (with an upload token) or any S3 tool. Each file is either **public** or **private**, and goes out through a public URL, a temporary link or a share link.

<BlobFlow
  labels={{
alt: "Files enter Blob Storage from your app, the browser or S3 tools, and leave through a public URL, a temporary link or a share link.",
app: "Your app",
appSub: "REST API + API key",
browser: "Browser",
browserSub: "Upload token",
s3: "S3 tools",
s3Sub: "aws-cli, boto3, rclone",
core: "Blob Storage",
pub: "Public URL",
pubSub: "Global CDN, permanent",
tmp: "Temporary link",
tmpSub: "Up to 24 hours",
share: "Share link",
shareSub: "Up to 30 days, revocable",
}}
/>

## Storage and pricing

Storage comes with your plan, and there are no transfer fees: you only ever pay for what stays stored above the quota.

### Included storage

Every plan includes storage at no extra cost, and it grows with the plan:

| Plan | Storage included |
| - | - |
| Hobby-1 | **5 GB** |
| Hobby-2 | **15 GB** |
| Standard-4 | **30 GB** |
| Standard-6 | **50 GB** |
| Standard-8 | **100 GB** |
| Pro-12 | **200 GB** |
| Pro-16 and up, Enterprise included | **250 GB** |

### Reaching your quota

When your usage reaches the included quota, **new uploads are refused** with `STORAGE_QUOTA_EXCEEDED` until you free space or upgrade your plan. Everything already stored keeps being served normally. Storage held **above** the quota (for example after a plan downgrade) is priced at:

<Card title="Storage above the quota" icon="coins">
  **R\$ 0.20 per started GiB** beyond your included quota.
</Card>

<Info>[Account Stats](/en/blob-reference/endpoint/stats) reports your current usage, this month's average and the estimated cost of any storage held beyond the quota.</Info>

<Info>Blob Storage is **only available** with an **active plan**. An account without an active plan can still list, download, delete and make files private. When a plan expires or is canceled, stored files enter a **deletion queue**, so renew as soon as possible: files already deleted can't be recovered.</Info>

### Features by plan

Every plan gets the full API: public and private files, temporary links, share links, the S3 gateway, upload tokens and rules per prefix. A few options depend on the plan, and all of them answer the same `403 UPGRADE_REQUIRED` code, with a `message` naming the plan (or the limit) that applies:

| Feature | Available on |
| - | - |
| Rules per prefix | **5** on Hobby and Standard, **10** on Pro, **20** on Enterprise |
| Uploads without the 1-per-second limit | Pro and Enterprise |
| Custom metadata (up to 5 keys, 512 bytes) | Pro and Enterprise |
| Password-protected share links | Pro and Enterprise |
| Expiries and automatic deletion under 7 days (down to 1 hour) | Enterprise |
| Files served without edge cache (`no-cache`) | Enterprise |

## Public and private files

Every object is either **public** or **private**, and its `id` says which: `pub/<user_id>/<path>` or `prv/<user_id>/<path>`.

* **Public files** have a permanent CDN URL: `https://blob.squarecloud.dev/pub/<user_id>/<path>`.
* **Private files** have no public URL (`url` is `null`). You read them through a [temporary link](/en/blob-reference/endpoint/download), a [share link](/en/blob-reference/endpoint/shares-create), the API or the [S3 gateway](/en/blob-reference/s3-compatibility).
* Legacy files, uploaded before the September 2026 update, keep their original id `<user_id>/<path>`, and every route accepts it. Their original URL on `https://public-blob.squarecloud.dev/<user_id>/<path>` keeps working for **30 days, until October 25, 2026**: move them with [Object Copy](/en/blob-reference/endpoint/copy) (`move: true`) to get a URL on `blob.squarecloud.dev`.

Read [Links and sharing](/en/blob-reference/links-and-sharing) for how publishing, unpublishing and the different kinds of links behave.

## Supported file types

Practically **any file type is accepted**, including formats with no registered MIME type: `.bam`, `.vcf`, `.fasta`, `.fastq`, `.parquet`, `.h5`, `.npy` and so on. The stored extension comes from the **filename you upload**, and compound compression suffixes are preserved (`reads.fastq.gz` stays `.fastq.gz`).

The only exception is a denylist of **executables and installers** (`.exe`, `.msi`, `.bat`, `.apk` and similar), refused with `BLOCKED_FILE_TYPE`.

<Warning>
  **Serving is safe by design**: the served `Content-Type` is derived server-side, never from the client. Unknown formats and browser-renderable types (`.html`, `.svg`, `.xml`) are always served as **downloads** (`application/octet-stream`), so malicious uploads never render in the browser.
</Warning>

## Performance and durability

Blob Storage went through **extensive benchmarks** before launch. Key findings:

* **Latency**: files are received in **\~11 ms** on average.
* **Durability**: designed for **99.999999999% (11 nines)**.
* **Edge delivery**: public files are cached at the CDN edge, so repeated reads never travel back to the origin.
* **Health check**: `https://blob.squarecloud.dev/pub/status` answers `OK` and is never cached, so you can point your monitoring at it.

<Frame>
  <img src="https://cdn.squarecloud.app/docs/services/blob-global-latency-test.webp" alt="Blob Storage global latency benchmark" style={{ borderRadius: "0.5rem" }} />
</Frame>

<Info>**Note**: Benchmark results come from controlled tests and vary with **geographic location**, **file size**, **network quality** and **peak usage**. For the most accurate numbers, test from your production environment.</Info>
<Warning>**Regional Limitations**: Users in **Africa** and some **Asian regions** may see higher latencies due to **physical distance from data centers** and **local network infrastructure**.</Warning>

## How to host your files

<Steps>
  <Step title="Get an API key">
    Create an API key with the `blob:write` scope in your [account settings](https://squarecloud.app/en/account/security). See [Authentication](/en/blob-reference/authentication).
  </Step>

  <Step title="Upload">
    Send files up to **100 MB** to [Object Post](/en/blob-reference/endpoint/post). Larger files, up to **10 GiB**, go through the [chunked upload flow](/en/blob-reference/endpoint/chunked-init). Prefer S3 tools? Point them at the [S3 gateway](/en/blob-reference/s3-compatibility) instead.
  </Step>

  <Step title="Serve">
    Use the `url` from the response for public files, or create a [temporary link](/en/blob-reference/endpoint/download) or a [share link](/en/blob-reference/endpoint/shares-create) for private ones.
  </Step>
</Steps>

For a first upload and download with curl, follow the [Blob Storage API quickstart](/en/blob-reference/quickstart).

<Tip>
  Using JavaScript? The [Blob SDK](/en/sdks/blob/client) (`@squarecloud/blob`) handles simple and multipart uploads, links, shares, rules and the S3 gateway for you, on Node.js and in the browser.
</Tip>

## Frequently asked questions

<AccordionGroup>
  <Accordion title="Which plan do I need for Blob Storage?">
    Blob Storage is available on any **plan**, Hobby and up, each with its own included storage quota (see the table above). See [Plans and Pricing](/en/platform/plans) for the full comparison.
  </Accordion>

  <Accordion title="What happens when I reach my included storage quota?">
    New uploads are refused with `STORAGE_QUOTA_EXCEEDED` until you delete objects or upgrade your plan. Everything already stored keeps being served normally. Storage held above the quota (for example after a downgrade) is priced at **R\$ 0.20 per started GiB**, and [Account Stats](/en/blob-reference/endpoint/stats) shows the estimate at any time.
  </Accordion>

  <Accordion title="Temporary link or share link?">
    A [temporary link](/en/blob-reference/endpoint/download) is valid for **up to 24 hours** and **cannot be revoked**: use it to hand a file to a user right now. A [share link](/en/blob-reference/endpoint/shares-create) lasts **up to 30 days**, **can be revoked**, can cap the number of downloads and, on Pro and Enterprise, can ask for a password. See [Links and sharing](/en/blob-reference/links-and-sharing).
  </Accordion>

  <Accordion title="Can I use S3 tools?">
    Yes. The [S3 gateway](/en/blob-reference/s3-compatibility) at `https://s3-blob.squarecloud.app` works with aws-cli, boto3, rclone and the AWS SDKs. Get the access key pair from [S3 Credentials](/en/blob-reference/endpoint/s3-credentials): it is derived from your API key, so revoking the key revokes the pair.
  </Accordion>

  <Accordion title="Which features depend on the plan?">
    Every plan gets rules per prefix (5 on Hobby and Standard, 10 on Pro, 20 on Enterprise). Custom metadata and password-protected share links need **Pro or Enterprise**. Expiries and automatic deletion under 7 days, and files served without edge cache, need **Enterprise**. Outside those plans the request is refused with `403 UPGRADE_REQUIRED`, and its `message` names the plan that unlocks the feature.
  </Accordion>

  <Accordion title="Do my old file URLs still work?">
    For 30 days. Legacy files, uploaded before the September 2026 update, keep their URL on `public-blob.squarecloud.dev` until **October 25, 2026**, and their id `<user_id>/<path>` keeps working on every route. To keep a public link after that, move the file with [Object Copy](/en/blob-reference/endpoint/copy) (`move: true`): new files are served from `blob.squarecloud.dev/pub/...`, and their id starts with `pub/` or `prv/`.
  </Accordion>
</AccordionGroup>


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