tigris-egress-optimizer

v2026.09.24

Use when diagnosing high storage costs, reducing egress/bandwidth, optimizing data transfer — covers caching, CDN, presigned URLs, Cache-Control headers

GitHub
安装命令
npx skhub add tigrisdata/tigris-egress-optimizer
Markdown
SKILL.md

Tigris Egress Optimizer

Diagnose and fix excessive storage egress (network data transfer) costs. Follow this 4-step framework to identify anti-patterns, apply fixes, and verify savings.

Most high egress bills come from the application fetching more data than it uses — not from infrastructure issues.

Prerequisites

Before doing anything else, install the Tigris CLI if it's not already available:

tigris help || npm install -g @tigrisdata/cli

If you need to install it, tell the user: "I'm installing the Tigris CLI (@tigrisdata/cli) so we can work with Tigris object storage."


Step 1: Diagnose

Identify which buckets and access patterns consume the most bandwidth.

Check Bandwidth Metrics

# Check bucket usage
tigris usage

# List objects by size (find large files being served frequently)
tigris ls t3://my-bucket --recursive -l | sort -k3 -rn | head -20

Questions to Answer

  • Which buckets have the highest bandwidth?
  • Are large files being downloaded repeatedly?
  • Are objects being accessed through the app server or directly?
  • Are there objects being downloaded that are never displayed to users?

Step 2: Analyze Codebase

Check your application code for these common anti-patterns:

Anti-Pattern Checklist

Anti-PatternSymptomImpact
Downloading full objects for metadataUsing get() when head() would sufficeHigh — downloads entire file
Re-downloading immutable assetsNo caching layer for static contentHigh — repeated bandwidth
Proxying through app serverServer downloads then re-serves to client2x bandwidth (Tigris→server + server→client)
Missing Cache-Control headersBrowsers re-fetch on every page loadVery high — multiplied by users
Not using CDNPrivate bucket for public contentMedium — single origin, no edge caching
Downloading full objects for thumbnailsFetching 5MB image to show 100px thumbnailHigh — 50x more data than needed

Code Search

Look for these patterns in your codebase:

# Downloads that should be head() calls
grep -rn "get(" --include="*.ts" --include="*.js" | grep -v "test"

# Missing cache headers on put()
grep -rn "put(" --include="*.ts" --include="*.js" | grep -v "cacheControl\|Cache-Control"

# Server-side file proxying
grep -rn "pipe\|stream\|createReadStream" --include="*.ts" --include="*.js"

Step 3: Fix

Fix 1: Use head() Instead of get() for Metadata

// Before — downloads entire file just to check if it exists
const result = await get("avatars/user-123.jpg", "file");
if (result.error) console.log("not found");

// After — only fetches metadata (size, contentType, modified)
const result = await head("avatars/user-123.jpg");
if (result.error) console.log("not found");
console.log(result.data?.size, result.data?.contentType);

Fix 2: Add Cache-Control Headers

// Set cache headers on upload
await put("assets/logo.png", file, {
  access: "public",
  contentType: "image/png",
});

Recommended cache values:

Content TypeCache-Control
Hashed assets (JS, CSS)public, max-age=31536000, immutable
Images (avatars, uploads)public, max-age=86400 (1 day)
Dynamic contentprivate, no-cache
Fontspublic, max-age=31536000, immutable

Fix 3: Use Public Buckets for CDN

Tigris public buckets automatically serve from the nearest global edge — no separate CDN setup needed.

# Make bucket public
tigris buckets create my-public-assets --public

# Or update existing bucket
tigris buckets update my-bucket --public

Public bucket URLs are served from Tigris's global edge network. This eliminates the need for CloudFront, Cloudflare, or other CDN layers for basic static asset delivery.

Fix 4: Use Presigned URLs (Skip Server Proxy)

// Before — server downloads file, then sends to client (2x egress)
app.get("/download/:path", async (req, res) => {
  const result = await get(req.params.path, "stream");
  result.data.pipe(res);
});

// After — redirect client to download directly from Tigris (1x egress)
app.get("/download/:path", async (req, res) => {
  const result = await getPresignedUrl(req.params.path, {
    operation: "get",
    expiresIn: 300,
  });
  res.redirect(result.data!.url);
});

Fix 5: Store Thumbnails Separately

// Before — serving 5MB original for a 100px avatar
<img src="/api/files/avatars/user-123.jpg" width="100" />

// After — generate and store thumbnail on upload
import sharp from "sharp";

const thumb = await sharp(originalBuffer)
  .resize(100, 100, { fit: "cover" })
  .jpeg({ quality: 80 })
  .toBuffer();

await put("avatars/user-123-thumb.jpg", thumb, {
  access: "public",
  contentType: "image/jpeg",
});
// Serve the 5KB thumbnail instead of the 5MB original

Fix 6: Client-Side Caching with ETags

// Server returns ETag on first request
app.get("/api/config", async (req, res) => {
  const result = await head("config/app.json");
  const etag = result.data?.modified?.toISOString();

  if (req.headers["if-none-match"] === etag) {
    return res.status(304).end(); // No body sent, no egress
  }

  const file = await get("config/app.json", "string");
  res.set("ETag", etag);
  res.json(JSON.parse(file.data));
});

Fix 7: Regional Pinning

Keep data close to compute to reduce cross-region transfer:

# Pin bucket to specific regions
tigris buckets create my-bucket --locations us-east-1,eu-west-1

Step 4: Verify

After applying fixes:

  1. Monitor bandwidth — check Tigris dashboard for bandwidth reduction
  2. Compare before/after — track bandwidth for 1-2 weeks
  3. Set alerts — configure monitoring for unexpected bandwidth spikes
  4. Review periodically — new features can introduce new anti-patterns

Quick Wins Summary

FixEffortImpact
Add Cache-Control headersLowHigh
Switch to public bucket (CDN)LowHigh
Use presigned URLs instead of proxyingMediumHigh
Replace get() with head() for checksLowMedium
Store thumbnails separatelyMediumHigh
Regional pinningLowMedium

Critical Rules

Always: Use public buckets for content served to users | Set Cache-Control headers on every upload | Use presigned URLs for private file downloads | Use head() for existence/metadata checks

Never: Proxy files through your app server when presigned URLs work | Serve original images when thumbnails suffice | Skip caching for immutable assets | Ignore bandwidth metrics


Related Skills

  • tigris-image-optimization — Generate thumbnails and variants
  • tigris-static-assets — CDN delivery with cache headers
  • tigris-lifecycle-management — Move cold data to cheaper tiers

Official Documentation

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/tigris-egress-optimizer

默认分支

main

最新提交

668ea42

Tree SHA

0e26190