media-drive
v3.2.0
Published
Modular TypeScript media library for Node.js with Prisma ORM. Extensible storage drivers (local, S3, BunnyCDN), image conversions via Sharp, async job processing with BullMQ, built-in multipart parsing, file validation, and flexible configuration. Inspire
Maintainers
Readme
Media Drive v3.2.0
Modular, TypeScript-first media library for Node.js applications
Inspired by Laravel Media Library
Upgrading?
- From v3.1.x? See CHANGELOG.md - v3.2.0 has breaking changes for HTTP API consumers (response format changed)
- From v2.x? See the V3 Migration & Feature Guide - v3.0 introduces stored file paths to support non-deterministic path generators
- From v1.x? See V2 Migration Guide
Quick links:
- CHANGELOG.md - Latest changes and breaking changes
- Full V3 Feature Guide - Complete overview with examples
- V2 Migration Guide - If upgrading from v1
Features
- Modular Architecture - Plug in your own storage drivers, processors, or queues
- Type-Safe Configuration - Zod-validated config with TypeScript inference
- Multiple Storage Drivers - Local, S3, BunnyCDN built-in
- Image Processing - Sharp-powered conversions with async job support
- Async Job Processing - BullMQ integration for background tasks
- Security - MIME type validation, file size limits, signed URLs
- CLI Tools - Generate configs, run diagnostics, manage migrations
- Backward Compatible - Programmatic API remains unchanged from v1
v3 Enhanced Features (EnhancedMediaLibrary)
- Built-in Multipart Parsing - No multer dependency needed
- File Validation - MIME types, content validation, size limits
- REST API - Auto-generated endpoints for upload, download, list, delete
- Upload Progress - Built-in progress tracking
- Error Handling - Express-compatible error middleware
- Standardized API Responses - Consistent response format with HTTP response helpers
- Multi-Disk Support - Pre-initialized storage drivers and dynamic disk selection
Installation
npm install media-drivePeer Dependencies
npm install @prisma/client prismaQuick Start
New to v3? We offer two setups: Standard (use with multer) and Enhanced (built-in multipart + validation). See Choosing Your Setup to decide.
1. Initialize
npx media-drive init
npx media-drive migrate
npx prisma migrate dev
npx prisma generate2. Configure
// media.config.ts
import { defineConfig } from "media-drive";
export default defineConfig({
disk: "local",
disks: {
local: {
driver: "local",
root: "uploads",
public_base_url: "http://localhost:3000/uploads",
},
},
});3. Use
Option A: Standard (with multer)
import { createMediaLibrary } from "media-drive";
import multer from "multer";
const upload = multer({ storage: multer.memoryStorage() });
const mediaLibrary = createMediaLibrary({ prisma });
app.post("/upload", upload.single("file"), async (req, res) => {
const media = await mediaLibrary.attachFile("User", "123", req.file!, {
collection: "avatar",
conversions: { thumb: { width: 150, height: 150 } },
});
res.json({ url: await mediaLibrary.resolveFileUrl(media.id) });
});Option B: Enhanced (no multer needed!)
import { createEnhancedMediaLibrary } from "media-drive";
const mediaLibrary = createEnhancedMediaLibrary({
config: {
disk: "local",
http: { enabled: true, multipart: { enabled: true } },
validation: {
fileTypes: { images: ["jpeg", "png"], documents: ["pdf"] },
},
},
});
app.post(
"/upload",
mediaLibrary.uploadMiddleware(), // Built-in multipart parsing!
async (req, res) => {
const result = await mediaLibrary.attachFromRequest(req, {
modelType: "User",
modelId: "123",
});
res.json(result);
}
);Which one? See Choosing Your Setup
Documentation
- Choosing Your Setup - Standard vs Enhanced: Which to use?
- Getting Started - Installation and basic usage
- Configuration - Complete configuration guide
- API Reference - Full API documentation
- Storage Drivers - Storage backend setup
- Advanced Usage - Custom drivers and strategies
- Examples - Real-world usage examples
- Troubleshooting - Common issues and solutions
- Architecture - System design and patterns
Architecture
Media Drive v3 features a clean, modular architecture:
src/
core/ # Core contracts & primitives
contracts/ # Public interfaces
errors/ # Custom error types
logger/ # Logging facade
responders/ # HTTP response helpers
utils/ # Shared utilities
config/ # Zod-based configuration
registry/ # DI-lite registry
storage/ # Storage drivers
conversions/ # Image processors
queue/ # Async job drivers
strategies/ # File naming & path generation
media/ # Application services
validation/ # File validation framework
http/ # Express adapters
migration/ # Database migration utilities
cli/ # Command-line tools
factory.ts # Main factory function
types.ts # Shared TypeScript typesExtensibility
Easily swap or extend any component:
import { createMediaLibrary } from "media-drive";
import { MyCustomStorageDriver } from "./my-storage";
const mediaLibrary = createMediaLibrary({
providers: {
storageDriver: new MyCustomStorageDriver(),
conversionProcessor: new MyImageProcessor(),
queueDriver: new MyQueueDriver(),
},
});See Advanced Usage for creating custom drivers.
Testing
npm test # Run all tests
npm run test:coverage # With coverage reportTest Results:
- 59 tests passing
- 7 test suites
- 100% pass rate
Migration
From v1/v2
Media Drive v3 maintains backward compatibility for programmatic API:
// v1 (still works with deprecation warning)
import { initMediaLibrary, MediaLibrary } from "media-drive";
initMediaLibrary(config);
const service = new MediaLibrary(prisma);
// v2/v3 Standard (recommended for core features)
import { createMediaLibrary } from "media-drive";
const service = createMediaLibrary({ config, prisma });
// v3 Enhanced (recommended for HTTP features)
import { createEnhancedMediaLibrary } from "media-drive";
const service = createEnhancedMediaLibrary({ config, prisma });
app.use("/api/media", service.getRouter());All public methods (attachFile, attachFromUrl, list, remove, resolveFileUrl, etc.) remain unchanged.
From v3.1.x to v3.2.0
⚠️ Breaking Changes for HTTP API Consumers: Response format has changed. See CHANGELOG.md for migration guide.
- Error responses:
{ error: string }→{ success: false, message: string } - Upload responses: Data structure changed (now nested under
data.media) - Delete responses: Now includes
data: {}field
Programmatic API (MediaLibrary and EnhancedMediaLibrary methods) remains unchanged.
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See ARCHITECTURE.md for architecture details.
License
MIT © Dadda Abdelghafour
Acknowledgments
Inspired by Laravel Media Library by Spatie.
Stats
- 59 tests passing - 100% test coverage for core modules
- 6 Cursor Rules - AI-friendly codebase documentation
- 6 documentation guides - Comprehensive user docs
- 4 usage examples - Real-world implementation patterns
- 3 CLI commands - Easy setup and diagnostics
- Zero TypeScript errors - Strict mode compliant
- 54 KB bundle - Lightweight and tree-shakable
v3.2.0 - Enhanced HTTP features, built-in validation, REST API, and comprehensive response helpers.
