nest-multi-storage
v1.0.1
Published
A flexible multi-driver storage module for NestJS supporting S3, Azure Blob Storage, and Local File System
Maintainers
Readme
nest-multi-storage
A flexible multi-driver storage module for NestJS that supports Amazon S3, Azure Blob Storage, and Local File System with a unified API.
Features
- 🔌 Multiple Storage Drivers: Support for Local, S3, and Azure Blob Storage
- 💾 Multi-Disk Configuration: Configure multiple disks with different drivers
- 🔄 Unified API: Same interface for all storage operations
- 🔐 Signed URLs: Generate temporary access URLs for S3 and Azure
- 📦 Stream Support: Handle large files with streaming
- 🧩 NestJS Integration: Dynamic module with
forRootandforRootAsync
Installation
npm install nest-multi-storage
# Peer dependencies
npm install @nestjs/common @nestjs/coreQuick Start
1. Import and Configure
// app.module.ts
import { Module } from '@nestjs/common';
import { StorageModule } from 'nest-multi-storage';
@Module({
imports: [
StorageModule.forRoot({
default: 'local',
disks: {
local: {
driver: 'local',
basePath: './storage',
baseUrl: 'http://localhost:3000/files',
},
s3: {
driver: 's3',
region: 'ap-southeast-1',
bucket: 'my-bucket',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
},
azure: {
driver: 'azure',
connectionString: process.env.AZURE_STORAGE_CONNECTION_STRING!,
container: 'my-container',
},
},
}),
],
})
export class AppModule {}2. Use in Services
import { Injectable } from '@nestjs/common';
import { StorageService } from 'nest-multi-storage';
@Injectable()
export class FileService {
constructor(private storage: StorageService) {}
async uploadFile(file: Express.Multer.File) {
// Upload to default disk
const result = await this.storage.put(
`uploads/${file.originalname}`,
file.buffer,
{ contentType: file.mimetype },
);
return { url: result.url };
}
async uploadToS3(file: Express.Multer.File) {
// Upload to specific disk
const result = await this.storage
.disk('s3')
.put(`uploads/${file.originalname}`, file.buffer);
// Get signed URL (valid for 1 hour)
const signedUrl = await this.storage
.disk('s3')
.signedUrl(`uploads/${file.originalname}`, 3600);
return { url: result.url, signedUrl };
}
async getFile(path: string) {
// Check if file exists
if (await this.storage.exists(path)) {
return this.storage.get(path);
}
throw new Error('File not found');
}
async deleteFile(path: string) {
return this.storage.delete(path);
}
}Async Configuration
import { ConfigModule, ConfigService } from '@nestjs/config';
import { StorageModule } from 'nest-multi-storage';
@Module({
imports: [
ConfigModule.forRoot(),
StorageModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
default: config.get('STORAGE_DISK', 'local'),
disks: {
local: {
driver: 'local',
basePath: config.get('STORAGE_PATH', './storage'),
},
s3: {
driver: 's3',
region: config.get('AWS_REGION'),
bucket: config.get('AWS_BUCKET'),
credentials: {
accessKeyId: config.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),
},
},
},
}),
}),
],
})
export class AppModule {}API Reference
StorageService Methods
| Method | Description |
|--------|-------------|
| disk(name) | Switch to a specific disk |
| put(path, content, options?) | Store a file |
| get(path) | Get file content as Buffer |
| getStream(path) | Get file content as Readable stream |
| delete(path) | Delete a file |
| deleteMany(paths) | Delete multiple files |
| exists(path) | Check if file exists |
| url(path) | Get public URL |
| signedUrl(path, expiresIn?) | Get temporary signed URL |
| copy(from, to) | Copy a file |
| move(from, to) | Move a file |
| stat(path) | Get file statistics |
| list(prefix?) | List files |
Driver Configuration
Local Driver
{
driver: 'local',
basePath: './storage', // Required: Base directory for storage
baseUrl: 'http://...', // Optional: Public URL prefix
}S3 Driver
{
driver: 's3',
region: 'ap-southeast-1', // Required: AWS region
bucket: 'my-bucket', // Required: Bucket name
credentials: { // Optional: Use for explicit credentials
accessKeyId: '...',
secretAccessKey: '...',
},
endpoint: 'http://...', // Optional: Custom endpoint (MinIO, etc.)
forcePathStyle: false, // Optional: Use path-style URLs
cdnUrl: 'https://cdn...', // Optional: CDN URL for public files
signedUrlExpiry: 3600, // Optional: Default signed URL expiry (seconds)
}Azure Blob Storage Driver
{
driver: 'azure',
connectionString: '...', // Required: Azure connection string
container: 'my-container', // Required: Container name
accountName: 'account', // Optional: Explicit account name for SAS
sasUrlExpiry: 3600, // Optional: Default SAS URL expiry (seconds)
}Stream Support
import { createReadStream } from 'fs';
// Upload from stream
const fileStream = createReadStream('/path/to/large-file.zip');
await this.storage.put('backups/large-file.zip', fileStream);
// Download as stream
const downloadStream = await this.storage.getStream('backups/large-file.zip');
downloadStream.pipe(response); // Pipe to HTTP responseTesting
# Run tests
npm run test
# Run tests with coverage
npm run test:covLicense
MIT
