---
title: Box
description: Box via the official typed SDK. Translates virtual keys into nested folders under a configurable rootFolderId.
---

## Installation

`box-typescript-sdk-gen` is an optional peer dependency of `files-sdk` - install alongside the SDK so the adapter's imports resolve at runtime.

```package-install
files-sdk box-typescript-sdk-gen
```

## Usage

Box via the official `box-typescript-sdk-gen` SDK. Box files live by ID, not by path, so the adapter walks `rootFolderId` and translates virtual keys (`docs/a.txt`) into nested Box subfolders, auto-creating intermediate folders on `upload()`. Five auth shapes (pre-built client, developer token, OAuth refresh-token, Client Credentials Grant, JWT server auth) cover scripts, user apps, and enterprise installs - token lifecycle is handled by the SDK's built-in `Authentication` classes.

```ts lineNumbers
import { Files } from "files-sdk";
import { box } from "files-sdk/box";

// Server-side: Client Credentials Grant (recommended for backend services).
// The SDK manages access-token lifetime internally - no manual refresh
// bookkeeping in the adapter.
const files = new Files({
  adapter: box({
    ccg: {
      clientId: process.env.BOX_CLIENT_ID!,
      clientSecret: process.env.BOX_CLIENT_SECRET!,
      enterpriseId: process.env.BOX_ENTERPRISE_ID!,
    },
    rootFolderId: process.env.BOX_ROOT_FOLDER_ID, // defaults to "0" (account root)
    // publicByDefault: true → upload() also calls addShareLinkToFile and
    //                       url() returns the link's download_url.
  }),
});

// Other auth shapes the adapter accepts:
//   developerToken: process.env.BOX_DEVELOPER_TOKEN  // dev-console token
//   oauth: { clientId, clientSecret, refreshToken } // user-app flow
//   jwt:   { configJsonString }                     // JWT server auth
//   client: yourBoxClient                           // pre-built escape hatch
```

## Options

<AutoTypeTable
  path="../../packages/files-sdk/src/box/index.ts"
  name="BoxAdapterOptions"
/>

## Limitations

`list()` is not recursive - it returns immediate-children files only at `rootFolderId`. For deep enumeration, drop to `raw.folders.getFolderItems` and recurse manually.

## Compatibility

| Method | Status | Notes |
| --- | :-: | --- |
| `upload` | ⚠️ | Two-stage: walks/creates parent folders by ID under `rootFolderId`, then `uploads.uploadFile` (≤50 MB) or `chunkedUploads.uploadBigFile` (>50 MB). Re-uploads against existing leaf names route through `uploadFileVersion` (overwrite). Stream bodies are buffered up-front - Box's upload manager takes a Node `Readable`, not a Web stream. User `metadata` and `cacheControl` throw - Box exposes file metadata via classifications and metadata templates; drop to `raw.fileMetadata.*` if you need it. Pause/resume via `control` is in-process only — the chunked-upload commit needs a whole-file digest, so a token cannot resume in a new process. |
| `download` | ⚠️ | Resolves the file ID, then fetches `getDownloadFileUrl` for both buffered and streaming reads - the SDK's native `downloadFile` returns a Node `Readable` that's awkward to expose isomorphically, so the adapter routes through standard HTTP, which gives a `ReadableStream` body. |
| `delete` | ✅ |  |
| `list` | ⚠️ | Returns immediate-children files only at `rootFolderId` - no recursion, and subfolders are filtered out. `prefix` is filename-prefix only (matched client-side within the page). Pagination uses Box's offset, encoded as a numeric cursor string. |
| `search` | ⚠️ | Built on `listAll` — inherits this adapter's `list` behavior above. Client-side key match (glob, regex, substring, exact). |
| `head` | ⚠️ | Box doesn't store user-supplied content types on file content - `head()` returns a type inferred from the filename extension (or `application/octet-stream` when unknown). `size`, `etag`, and `lastModified` come from `getFileById`. |
| `exists` | ✅ |  |
| `copy` | ✅ |  |
| `url` | ⚠️ | Default mints a signed download URL via `getDownloadFileUrl` - Box controls the TTL server-side, so `expiresIn` is accepted for API symmetry but is not honoured. With `publicByDefault: true`, `upload()` calls `addShareLinkToFile` (open access) and `url()` returns the link's `download_url`. With `publicBaseUrl`, returns `<publicBaseUrl>/<key>`. `responseContentDisposition` always throws - Box's URLs have no Content-Disposition override. |
| `signedUploadUrl` | ❌ | Throws - Box uploads require a multipart POST with both an `attributes` JSON part and the file bytes part, which fits neither the SDK's PUT-with-headers nor S3-style POST-with-form-fields shape. Use `upload()` server-side, or Box's UI Elements / Content Uploader for browser flows. |
