file-storage について
Tigris Object Storageでファイルを保存・配信するためのスキルガイドです。CLIの設定、`@tigrisdata/storage` SDKによる操作、署名付きURLを使ったブラウザーアップロードを扱います。
主な機能
- 01Tigris CLIと認証情報の設定
- 02SDKによるオブジェクトのアップロードとダウンロード
- 03オブジェクトの一覧表示、確認、削除
- 04一時的な署名付きURLの作成
- 05進捗表示付きのブラウザーアップロード
活用シーン
- 01アプリ用のバケットとアクセスキーの設定
- 02ファイルのアップロード・ダウンロードフローの構築
- 03サーバーでファイル本体を中継せずブラウザーからアップロード
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tigrisdata/ skills --skill file-storageインストール後、Claude Code で/file-storageを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonREADME.mdresources/express.mdlaravel.mdnextjs.mdrails.mdremix.md詳細
Tigris ファイルストレージ
Tigris Object Storage を使ってファイルを保存、配信します。CLI のセットアップ(バケット、アクセスキー、認証)と、アプリケーションコード向けの @tigrisdata/storage SDK について説明します。
クイックスタート
# 1. Install CLI & authenticate
npm install -g @tigrisdata/cli
tigris login
# 2. Create bucket and access key
tigris buckets create my-app-uploads
tigris access-keys create "my-app-uploads-key"
# ⚠ Save the Secret Access Key — shown only once
tigris access-keys assign tid_xxx --bucket my-app-uploads --role Editor
# 3. Install SDK
npm install @tigrisdata/storage
# .env
TIGRIS_STORAGE_ACCESS_KEY_ID=tid_xxx
TIGRIS_STORAGE_SECRET_ACCESS_KEY=tsec_yyy
TIGRIS_STORAGE_ENDPOINT=https://t3.storage.dev
TIGRIS_STORAGE_BUCKET=my-app-uploads
import { put } from "@tigrisdata/storage";
// Files are private by default — only authenticated requests can access them
const result = await put("avatars/user-123.jpg", file);
if (result.error) throw result.error;
console.log(result.data?.url);
// Use access: "public" only when anonymous users need direct URL access
// const result = await put("avatars/user-123.jpg", file, { access: "public" });
詳しい手順については、以下の CLI を使った始め方 を参照してください。
CLI を使った始め方
手順 1:CLI をインストールする
npm install -g @tigrisdata/cli
インストールを確認します。
tigris --version
t3 は tigris のエイリアスです。どちらでもすべてのコマンドを実行できます。
手順 2:認証する
tigris login
OAuth のためにブラウザーが開きます。ログイン後、次のコマンドで確認します。
tigris whoami
CI/CD または非対話型の環境では、次のようにします。
tigris configure --access-key <key> --access-secret <secret>
手順 3:バケットを作成する
tigris buckets create my-app-uploads
ポイント:
- バケットはデフォルトでプライベートです。オブジェクトを公開読み取り可能にするには、
--publicを使用します。 - バケットはデフォルトでグローバルです。特定のリージョンに固定するには、
--locationsを使用します。 - コマンドの後に
helpと入力すると、そのコマンドのオプションを確認できます(例:tigris buckets create help)。
手順 4:アクセスキーを作成する
tigris access-keys create "my-app-uploads-key"
アクセスキー ID(tid_xxx)とシークレットアクセスキー(tsec_yyy)が出力されます。
シークレットアクセスキーが表示されるのは一度だけです。 すぐにコピーしてください。名前欄は人が識別するためだけのもので、機能には影響しません。
手順 5:環境を設定する
プロジェクトのルートに .env を作成します。
TIGRIS_STORAGE_ACCESS_KEY_ID=tid_xxx
TIGRIS_STORAGE_SECRET_ACCESS_KEY=tsec_yyy
TIGRIS_STORAGE_ENDPOINT=https://t3.storage.dev
TIGRIS_STORAGE_BUCKET=my-app-uploads
TIGRIS_STORAGE_BUCKET は、すべての SDK 呼び出しで使用するデフォルトのバケットを設定します。.env を .gitignore に追加し、認証情報を決してコミットしないでください。
手順 6:バケットにアクセスキーを割り当てる
tigris access-keys assign tid_xxx --bucket my-app-uploads --role Editor
ロール:
| ロール | 権限 | 用途 |
|---|---|---|
Editor | オブジェクトの読み取り+書き込み+削除 | ファイルをアップロード/削除するアプリサーバー |
ReadOnly | オブジェクトの読み取りのみ | ファイルの配信/ダウンロードのみを行うアプリ |
これで、以下が揃いました。
- バケット(
my-app-uploads) - アクセスキー(
tid_xxx/tsec_yyy) - Editor ロールでバケットに割り当てられたキー
- SDK で使用できる
.envファイル
手順 7:SDK をインストールする
npm install @tigrisdata/storage
# or
yarn add @tigrisdata/storage
ES Modules と CommonJS に対応しています。
SDK リファレンス
すべてのメソッドは TigrisStorageResponse<T, E> を返します。必ず最初に error を確認してください。
const result = await put("file.txt", "hello");
if (result.error) {
console.error(result.error);
return;
}
console.log(result.data);
config — デフォルト設定の上書き
すべてのメソッドは、TigrisStorageConfig 型の省略可能な config パラメーターを受け取ります。
type TigrisStorageConfig = {
bucket?: string; // Override TIGRIS_STORAGE_BUCKET
accessKeyId?: string; // Override TIGRIS_STORAGE_ACCESS_KEY_ID
secretAccessKey?: string; // Override TIGRIS_STORAGE_SECRET_ACCESS_KEY
endpoint?: string; // Override TIGRIS_STORAGE_ENDPOINT
};
config を使うと、呼び出しごとに別のバケットを指定したり、異なる認証情報を使用したりできます。
// Upload to a different bucket
await put("report.pdf", data, { config: { bucket: "reports-archive" } });
// Use a separate read-only key for downloads
await get("file.txt", "string", { config: { accessKeyId: "tid_ro", secretAccessKey: "tsec_ro" } });
put — アップロード
put(path: string, body: string | ReadableStream | Blob | Buffer, options?: PutOptions)
import { put } from "@tigrisdata/storage";
// Simple text upload
const result = await put("notes/hello.txt", "Hello, World!");
// Image with public access
const result = await put("avatars/user-123.jpg", file, {
access: "public",
contentType: "image/jpeg",
addRandomSuffix: false,
});
// Large file with multipart and progress
const result = await put("videos/demo.mp4", fileStream, {
multipart: true,
onUploadProgress: ({ loaded, total, percentage }) => {
console.log(`${loaded}/${total} bytes (${percentage}%)`);
},
});
// Prevent accidental overwrite
const result = await put("config.json", data, {
allowOverwrite: false,
});
Put オプション:
| オプション | 値 | デフォルト | 用途 |
|---|---|---|---|
| access | public, private | private | オブジェクトの公開範囲 |
| addRandomSuffix | boolean | false | 同名のユーザーアップロードファイルが衝突しないよう、ランダムなサフィックスを追加します |
| allowOverwrite | boolean | true | 既存ファイルの置き換えを許可します |
| contentType | MIME 文字列 | 推定 | コンテンツタイプヘッダー |
| contentDisposition | inline,attachment | inline | ブラウザーでの表示方法 |
| multipart | boolean | false | 大容量ファイルの場合に有効にします |
| onUploadProgress | コールバック | — | {loaded, total, percentage} |
| config | TigrisStorageConfig | — | バケット/認証情報を上書きします(上記の config セクションを参照) |
レスポンスデータ: { url, path, size, contentType, contentDisposition, modified }
get — ダウンロード
get(path: string, format: "string" | "file" | "stream", options?: GetOptions)
import { get } from "@tigrisdata/storage";
// Read as string (text, JSON)
const result = await get("notes/hello.txt", "string");
console.log(result.data); // "Hello, World!"
// Serve as file (for API routes)
const result = await get("avatars/user-123.jpg", "file", {
contentDisposition: "inline",
});
// Trigger browser download
const result = await get("reports/q4.pdf", "file", {
contentDisposition: "attachment",
});
// Stream large files
const result = await get("videos/demo.mp4", "stream");
Get のオプション:
| オプション | 値 | デフォルト | 用途 |
|---|---|---|---|
| contentDisposition | inline,attachment | inline | 表示とダウンロードの切り替え |
| contentType | MIME 文字列 | アップロード時の値 | コンテンツタイプを上書き |
| encoding | 文字列 | utf-8 | テキストエンコーディング |
| config | TigrisStorageConfig | — | バケット/認証情報を上書き(上記の設定セクションを参照) |
remove — 削除
remove(path: string, options?: RemoveOptions)
import { remove } from "@tigrisdata/storage";
const result = await remove("notes/hello.txt");
if (result.error) {
console.error(result.error);
}
list — オブジェクトの一覧表示
list(options?: ListOptions)
import { list } from "@tigrisdata/storage";
// List all objects
const result = await list();
console.log(result.data?.items);
// Filter by prefix
const result = await list({ prefix: "avatars/" });
// Paginate through all objects
const allFiles = [];
let page = await list({ limit: 100 });
allFiles.push(...(page.data?.items ?? []));
while (page.data?.hasMore) {
page = await list({
limit: 100,
paginationToken: page.data.paginationToken,
});
allFiles.push(...(page.data?.items ?? []));
}
List のオプション:
| オプション | 用途 |
|---|---|
| prefix | この文字列で始まるキーで絞り込む |
| delimiter | キーをグループ化(例:フォルダーの場合は"/") |
| limit | 1 ページあたりの最大オブジェクト数(デフォルト:100) |
| paginationToken | 前のページから続ける |
| config | TigrisStorageConfig — バケット/認証情報を上書き(上記の設定セクションを参照) |
レスポンスデータ: { items, paginationToken, hasMore }
head — オブジェクトのメタデータ
head(path: string, options?: HeadOptions)
import { head } from "@tigrisdata/storage";
const result = await head("avatars/user-123.jpg");
if (!result.error) {
console.log(result.data);
// { path, size, contentType, contentDisposition, modified, url }
}
getPresignedUrl — 一時 URL
getPresignedUrl(path: string, options: GetPresignedUrlOptions)
import { getPresignedUrl } from "@tigrisdata/storage";
// Temporary download link (1 hour)
const result = await getPresignedUrl("reports/q4.pdf", {
operation: "get",
expiresIn: 3600,
});
console.log(result.data?.url);
// Temporary upload link (10 minutes)
const result = await getPresignedUrl("uploads/photo.jpg", {
operation: "put",
expiresIn: 600,
});
Presigned URL のオプション:
| オプション | 値 | デフォルト | 用途 |
|---|---|---|---|
| operation | get,put | — | URL の用途 |
| expiresIn | 秒 | 3600 | 有効期限 |
| contentType | MIME 文字列 | — | PUT に必須 |
| config | TigrisStorageConfig | — | バケット/認証情報を上書き(上記の設定セクションを参照) |
レスポンスデータ: { url, method, expiresIn }
クライアントサイドアップロード
サーバー経由でバイトデータを転送せずに、ブラウザーから Tigris にファイルを直接アップロードできます。内部では Presigned URL を使用します。
サーバー — アップロードリクエストの処理
// app/api/upload/route.ts
import { NextRequest, NextResponse } from "next/server";
import { handleClientUpload } from "@tigrisdata/storage";
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { data, error } = await handleClientUpload(body);
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ data });
} catch (error) {
return NextResponse.json(
{ error: "Failed to process upload request" },
{ status: 500 },
);
}
}
クライアント — 直接アップロード
"use client";
import { upload } from "@tigrisdata/storage/client";
import { useState } from "react";
export default function FileUpload() {
const [progress, setProgress] = useState(0);
const [url, setUrl] = useState<string | null>(null);
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const result = await upload(file.name, file, {
url: "/api/upload",
access: "private",
multipart: true,
partSize: 10 * 1024 * 1024,
onUploadProgress: ({ percentage }) => {
setProgress(percentage);
},
});
setUrl(result.url);
};
return (
<>
<input type="file" onChange={handleFileChange} />
{progress > 0 && progress < 100 && <div>{progress}%</div>}
{url && <div>Uploaded: {url}</div>}
</>
);
}
クライアントアップロードのオプション:
| オプション | 必須 | 用途 |
|---|---|---|
| url | はい | Presigned URL 用のバックエンドエンドポイント |
| access | いいえ | public または private(デフォルト) |
| multipart | いいえ | 大きなファイルの場合に有効にする |
| partSize | いいえ | パートごとのバイト数(デフォルト:5 MiB) |
| concurrency | いいえ | パートの並列アップロード数(デフォルト:4) |
| contentType | いいえ | MIME タイプ |
| onUploadProgress | いいえ | {loaded, total, percentage} |
React コンポーネント(任意)
npm install @tigrisdata/react を実行すると、ファイル選択、進捗表示、エラー処理を組み込んだ、そのまま使える<Uploader>コンポーネントを利用できます。使い方については、@tigrisdata/react のドキュメントを参照してください。
重要なルール
必ず行うこと: result.data を確認する前に result.error を確認する | デフォルトではファイルを private としてアップロードする — 匿名ユーザーが URL に直接アクセスする必要がある場合に限り、access: "public" を設定する | ブラウザーからのアップロードには handleClientUpload を使用する(サーバー経由でバイトデータを転送しない) | 100MB を超えるファイルには multipart: true を使用する | hasMore と paginationToken を使って list() をページネーションする | ファイルを置き換える際は古いファイルを削除する(自動クリーンアップはありません) | 必要に応じて contentType を明示的に設定する
絶対に行わないこと: アクセスキーをクライアントに公開する(@tigrisdata/storage/client の handleClientUpload と upload() を使用する) | エラーチェックを省略する | file.jpg のような汎用的なパスを使用する(avatars/${userId}.jpg やタイムスタンプを使用する) | 作成時に Secret Access Key を保存し忘れる(一度しか表示されません)
既知の問題
| 問題 | 原因と対処 |
|---|---|
| アップロード時に「Access denied」と表示される | バケットにキーが割り当てられていません。tigris access-keys assign tid_xxx --bucket <name> --role Editor を実行してください |
| SDK から「Bucket not found」と表示される | .env のバケット名が間違っています。tigris buckets list で確認してください |
| Secret Access Key を紛失した | 復元できません。新しく作成し、再割り当てしてください:tigris access-keys create "new-key" |
| ファイルにパブリックアクセスできない | バケットはデフォルトでプライベートです。--public フラグを使うか、put() に access: "public" を指定してください |
| 大きなファイルのアップロードが停止する | 100MB を超えるファイルの場合は、put オプションに multipart: true を追加してください |
| List の結果が不完全 | デフォルトの上限は 100 です。ページネーションには hasMore と paginationToken を使用してください |
| クライアントのアップロードに失敗する(CORS/500) | サーバールートでは @tigrisdata/storage の handleClientUpload を使用する必要があります |
CLI クイックリファレンス
t3 は tigris のエイリアスです。オプションを確認するには、任意のコマンドの後に help と入力してください。
# Auth
tigris login
tigris whoami
# Buckets
tigris buckets create <name> [--public] [--locations <region>]
tigris buckets list
tigris buckets delete <name>
# Access keys
tigris access-keys create "<name>"
tigris access-keys assign <tid_xxx> --bucket <name> --role Editor
# Objects
tigris cp <src> <dest> [-r] # Upload/download/copy
tigris mv <src> <dest> [-rf] # Move or rename
tigris rm <path> [-rf] # Delete
tigris ls [bucket/prefix] # List
tigris stat <path> # Metadata
tigris presign <path> # Presigned URL
tigris touch <path> # Create empty object
リモートパスには t3:// プレフィックスを使用します:t3://my-bucket/path/file.txt
フレームワーク統合ガイド
フレームワーク固有のアップロード/ダウンロードのパターンについては、使用するフレームワークのリソースファイルをお読みください。
| フレームワーク | SDK | リソース |
|---|---|---|
| Next.js | @tigrisdata/storage(ネイティブ) | ./resources/nextjs.md を参照 — Server Actions、API Routes、next/image、クライアントアップロード |
| Remix | @tigrisdata/storage(ネイティブ) | ./resources/remix.md を参照 — アクション関数、ローダー、クライアントアップロード |
| Express | @tigrisdata/storage(ネイティブ) | ./resources/express.md を参照 — Multer、ストリーミングアップロード、クライアントアップロード |
| Rails | aws-sdk-s3(ネイティブの Ruby SDK はまだありません) | ./resources/rails.md を参照 — Active Storage、直接アップロード、画像バリアント |
| Django | tigris-boto3-ext + django-storages | tigris-python-sdk スキルを使用 — FileField、django-storages、署名付き URL を扱います |
| Laravel | league/flysystem-aws-s3-v3(ネイティブの PHP SDK はまだありません) | ./resources/laravel.md を参照 — Storage ファサード、Livewire アップロード、署名付き URL |
デプロイ
| フレームワーク | プラットフォーム | 環境変数の設定方法 |
|---|---|---|
| Next.js | Vercel | ダッシュボード → Settings → Environment Variables |
| Remix | Fly.io | fly secrets set TIGRIS_STORAGE_ACCESS_KEY_ID=... ... |
| Express | Docker | -e フラグまたは Compose の .env |
| Rails | Fly.io / Kamal | fly secrets set または kamal env push |
| Laravel | Forge / Vapor | ダッシュボード → Environment または vapor env:pull |
関連スキル
- tigris-python-sdk — boto3 による Python アクセス、Django アップロード、スナップショット、フォーク、Bundle API
- tigris-bucket-management — 高度なバケットオプション(リージョン、ティア、スナップショット)
- tigris-object-operations — SDK 関数の詳細リファレンス
- tigris-snapshots-forking — 特定時点への復旧とバケットのフォーク