One API for all your media uploads.
A unified, TypeScript-first media library for modern applications. Upload to Cloudinary, S3, R2, and more with a single interface.
- Unified API - Write once, use any provider
- Type-safe - Full TypeScript support with intelligent autocomplete
- Tree-shakeable - Only bundle what you use
- React integration - Hooks and components included
- Extensible - Plugin system and native provider API access
- Lightweight - Lazy loading and dynamic imports for minimal bundle size
# Install core + provider
pnpm add @fluxmedia/core @fluxmedia/cloudinary cloudinaryimport { MediaUploader } from '@fluxmedia/core';
import { CloudinaryProvider } from '@fluxmedia/cloudinary';
const uploader = new MediaUploader(
new CloudinaryProvider({
cloudName: 'your-cloud',
apiKey: 'your-key',
apiSecret: 'your-secret',
})
);
const result = await uploader.upload(file, {
folder: 'avatars',
transformation: {
width: 400,
height: 400,
fit: 'cover',
format: 'webp',
},
});
console.log(result.url);| Package | Description | Size |
|---|---|---|
| @fluxmedia/core | Core types and abstractions | ~13KB |
| @fluxmedia/cloudinary | Cloudinary provider | ~14KB |
| @fluxmedia/s3 | AWS S3 provider | ~11KB |
| @fluxmedia/r2 | Cloudflare R2 provider | ~12KB |
| @fluxmedia/plugins | Official plugins | ~20KB |
| @fluxmedia/react | React hooks and components | ~9KB |
Use the same code regardless of which provider you choose:
// Cloudinary
const uploader = new MediaUploader(new CloudinaryProvider({ ... }));
// S3
const uploader = new MediaUploader(new S3Provider({ ... }));
// R2
const uploader = new MediaUploader(new R2Provider({ ... }));
// Use the same API everywhere
await uploader.upload(file);Full type safety and IntelliSense support:
const result = await uploader.upload(file);
// result.url - autocomplete knows all properties
// result.width, result.height, result.format, etc.Tree-shakeable architecture with lazy loading:
- Core: ~13KB (minified, excludes SDK)
- Provider packages: ~11-14KB each (excludes SDK)
- Plugins: ~20KB (all 5 plugins)
- Basic Node.js - All providers, plugins, and core features
- Next.js App - Full Next.js integration with all providers
pnpm add @fluxmedia/reactimport { useMediaUpload } from '@fluxmedia/react';
function UploadButton() {
const { upload, uploading, progress, error, result } = useMediaUpload({
mode: 'signed',
signUrlEndpoint: '/api/media/sign'
});
return (
<div>
<input
type="file"
onChange={(e) => upload(e.target.files?.[0])}
disabled={uploading}
/>
{uploading && <progress value={progress} max={100} />}
{result && <img src={result.url} alt="Uploaded" />}
{error && <div>Error: {error.message}</div>}
</div>
);
}pnpm add @fluxmedia/pluginsAvailable plugins:
- File Validation - Validate types, sizes, extensions
- Image Optimization - Resize, format, quality (requires sharp)
- Metadata Extraction - EXIF, dimensions, hashing
- Analytics - Logging and tracking with typed events
- Retry - Automatic retry with exponential backoff
| Feature | Cloudinary | S3 | R2 |
|---|---|---|---|
| Image Transformations | Yes | No | No |
| Video Processing | Yes | No | No |
| AI Tagging | Yes | No | No |
| Multipart Upload | Yes | Yes | Yes |
| Direct Upload | Yes | Yes | Yes |
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Lint
pnpm lintWe welcome contributions! Please see CONTRIBUTING.md for details.
MIT © FluxMedia Contributors
Built with TypeScript