Shop It Docs
Developer Resources

Storage Service Setup

Central place to configure uploads for both local disk and object storage (S3-compatible) deployments used by `@nomor/storage` and the Nest API module.

Storage Service Setup

Central place to configure uploads for both local disk and object storage (S3-compatible) deployments used by @nomor/storage and the Nest API module.

1. Install Dependencies

Already added to the monorepo, but make sure the workspace has these packages:

  • @nomor/storage (workspace package)
  • @aws-sdk/client-s3
  • sharp
  • zod

Run pnpm install at the repo root if you have not pulled the updated lockfile.

2. Environment Variables

All envs live in apps/api/.env (or use apps/api/sample.env as a template).

env
# Local storage roots
UPLOAD_LOCATION=apps/api/uploads

# Object storage / S3 (optional)
STORAGE_BUCKET_ENDPOINT=http://localhost:9000
STORAGE_BUCKET_ACCESS_KEY=your_access_key
STORAGE_BUCKET_SECRET_KEY=your_secret_key
STORAGE_BUCKET_NAME=portfolio-storage
STORAGE_BUCKET_REGION=us-east-1
STORAGE_BUCKET_PUBLIC_URL=http://localhost:9000

Leave the object storage variables empty to stay on local disk only.

3. Local Disk Only

  1. Ensure UPLOAD_LOCATION points to the writable directory (apps/api/uploads by default).
  2. Run the Nest API once or call StorageManager.ensureLocalStructure() to create the image, video, file, pdf, and xlsx folders.
  3. Uploads stay inside the repo and responses include localPath / relativePath values.

4. Object storage / S3

  1. Set the object storage env vars above. STORAGE_BUCKET_PUBLIC_URL is optional; when provided, response URLs use it instead of the raw endpoint.
  2. Restart the API after updating envs so the StorageManager picks up the remote config.
  3. Upload responses now include remoteKey and remoteUrl pointing at the bucket while still retaining the local relative path.

5. Runtime Behavior

  • All files are uploaded using Multer to the local UPLOAD_LOCATION first.
  • StorageManager optimizes images to WebP (quality 85, effort 6) when optimize=true.
  • When object storage is configured, the optimized file is pushed via AWS SDK v3 and the temporary local file is deleted (set cleanupLocalOnSuccess: false when instantiating StorageManager if you need to keep it).
  • When a remote upload fails and fallback is disabled, the temporary file is also removed to keep the API host stateless (cleanupLocalOnFailure defaults to true when object storage is enabled).
  • Fallback to disk only happens when object storage is not configured. If a remote upload fails, StorageManager throws StorageUploadFailedError so the caller can surface the error to clients.

6. Using the Storage Manager Elsewhere

import { StorageManager } from "@nomor/storage";

const storage = new StorageManager();
await storage.ensureLocalStructure();
const result = await storage.handleUpload(file, { optimize: true });

This shared package allows other apps in the monorepo to reuse the same configuration surface.