Skip to content
ChatJS
Esc
navigateopen⌘Jpreview
On this page

Custom Storage

Publish a third-party storage integration using the standard ChatJS registry contract

Your item installs one entry point at ~/lib/storage-provider.ts. Export a synchronous createStorageAdapter(options) function returning a Files SDK Adapter. You can wrap an existing Files SDK provider or implement its adapter interface. Your provider ID does not need to exist in the built-in catalog.

Author source

For an S3-based integration with your own configuration shape:

import { s3 } from "files-sdk/s3";

export function createStorageAdapter(options: {
  bucket: string;
  region: string;
}) {
  return s3(options);
}

The receiving app generates storage-options.ts with storageOptions satisfies Parameters<typeof createStorageAdapter>[0]. Its shared file layer passes those options to your factory and wraps the returned adapter in Files. Type-check the installed app to verify both contracts.

Read custom credentials inside your adapter from its documented environment variables. Creating the factory should not upload files or perform other remote operations. The installer reads metadata, without executing your source.

Declare the registry item

Use standard shadcn files and dependencies, plus this meta.chatjs shape:

{
  "contractVersion": 1,
  "kind": "storage",
  "id": "acme-storage",
  "configKeys": ["bucket", "region"],
  "envRequirements": [{ "options": [["ACME_STORAGE_TOKEN"]] }],
  "optionalEnv": []
}

configKeys supplies configuration hints for the CLI prompt. TypeScript checks the actual option shape. Each environment requirement must be satisfied. Its options are alternatives, with every variable in one alternative required. Declare variables your implementation actually reads. For the S3 wrapper above, use S3’s configuration and credential requirements instead of the illustrative ACME_STORAGE_TOKEN.

Declare files-sdk and your provider’s peer packages under dependencies. List the source file with type: "registry:file" and target: "~/lib/storage-provider.ts". Extra implementation files and shared registry dependencies are supported through standard shadcn fields. The CLI owns lib/storage-options.ts, so your item should not install that file.

Install and verify

Publish the generated JSON through your registry, then run:

npx @chat-js/cli@latest create my-app --yes \
  --storage-provider https://example.com/r/acme-storage.json \
  --storage-config '{"bucket":"uploads","region":"us-east-1"}'

Namespace addresses such as @acme/storage also work when configured in components.json at the resolution location. A complete URL works before the new app has a namespace configuration.

Run the receiving app’s type checks and check-env, then verify upload, download, and deletion with your adapter. Metadata validation alone cannot prove that credentials, network access, or storage operations work.

This selection flow applies to app creation. chat-js add and sync still handle tools. Switching a deployed app’s storage requires a separate object migration and configuration change, as described in File Storage.

Last updated on Sep 9, 2026

Was this page helpful?