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

# storage — EdgeSpark file storage

> Use the EdgeSpark storage import for R2 buckets, S3 URIs, metadata reads, pagination, and presigned upload or download URLs.

`storage` provides access to your project's R2 buckets. Import it from `edgespark` and pass bucket declarations from `@defs`.

## `storage.from(bucket)`

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { buckets } from "@defs";

const uploads = storage.from(buckets.uploads);
```

## S3 URI helpers

Use S3 URIs when you want to persist a file reference in your own database:

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { buckets } from "@defs";

const avatarS3Uri = storage.createS3Uri(buckets.uploads, "avatars/user-1.png");

if (storage.isS3Uri(avatarS3Uri)) {
  const parsed = storage.parseS3Uri(avatarS3Uri);
  console.log(parsed.bucket.bucket_name, parsed.path);
}
```

If the input may be invalid, use `tryParseS3Uri(...)`:

```typescript theme={null}
const parsed = storage.tryParseS3Uri(inputFromDatabaseOrWebhook);

if (!parsed) {
  throw new Error("Invalid S3 URI");
}
```

## Upload and download

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { buckets } from "@defs";

await storage
  .from(buckets.uploads)
  .put("reports/q1.pdf", new TextEncoder().encode("report"));

const object = await storage.from(buckets.uploads).get("reports/q1.pdf");
if (!object) throw new Error("Not found");
```

## Read metadata without downloading the file

Use `head(...)` when you only need metadata:

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { buckets } from "@defs";

const meta = await storage.from(buckets.uploads).head("reports/q1.pdf");

if (meta) {
  console.log(meta.size, meta.contentType);
}
```

## List and delete

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { buckets } from "@defs";

const files = await storage.from(buckets.uploads).list({ prefix: "reports/" });
await storage.from(buckets.uploads).delete("reports/q1.pdf");
```

`delete(...)` also accepts multiple paths:

```typescript theme={null}
await storage.from(buckets.uploads).delete([
  "reports/q1.pdf",
  "reports/q2.pdf",
]);
```

## Paginate or group list results

`list(...)` supports pagination and delimiter-based grouping:

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { buckets } from "@defs";

const page = await storage.from(buckets.uploads).list({
  prefix: "reports/",
  limit: 100,
  delimiter: "/",
});

console.log(page.files, page.delimitedPrefixes, page.cursor);
```

## Presigned uploads

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { auth } from "edgespark/http";
import { Hono } from "hono";
import { buckets } from "@defs";

const app = new Hono().post("/api/upload-url", async (c) => {
  const { filename, contentType } = await c.req.json<{
    filename: string;
    contentType?: string;
  }>();

  const { uploadUrl, requiredHeaders } = await storage
    .from(buckets.uploads)
    .createPresignedPutUrl(`user-files/${auth.user.id}/${filename}`, 3600, {
      contentType,
    });

  return c.json({ uploadUrl, requiredHeaders });
});

export default app;
```

## Presigned downloads

```typescript server/src/index.ts theme={null}
import { storage } from "edgespark";
import { Hono } from "hono";
import { buckets } from "@defs";

const app = new Hono().get("/api/download/:key", async (c) => {
  const { downloadUrl } = await storage
    .from(buckets.uploads)
    .createPresignedGetUrl(c.req.param("key"), 3600);

  return c.json({ downloadUrl });
});

export default app;
```

<Tip>
  Use presigned URLs for large client uploads and downloads. See [platform limits](/reference/limits) for file size and runtime constraints.
</Tip>

## See also

<Columns cols={2}>
  <Card title="Use storage" icon="book" href="/guides/storage">
    Declare buckets, apply them with the CLI, and use storage from your routes.
  </Card>

  <Card title="Build a REST API" icon="rocket" href="/tutorials/build-a-rest-api">
    Complete example with presigned uploads and file references.
  </Card>
</Columns>
