file-upload

Node.js (Multer — recommended)

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "file-upload" with this command: npx skills add claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-file-upload

File Upload Handling

Node.js (Multer — recommended)

import multer from 'multer'; import path from 'path'; import crypto from 'crypto';

// Storage configuration const storage = multer.diskStorage({ destination: './uploads', filename: (req, file, cb) => { const uniqueName = ${crypto.randomUUID()}${path.extname(file.originalname)}; cb(null, uniqueName); }, });

// File filter const fileFilter = (req: Express.Request, file: Express.Multer.File, cb: multer.FileFilterCallback) => { const allowedMimes = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf']; if (allowedMimes.includes(file.mimetype)) { cb(null, true); } else { cb(new Error(File type ${file.mimetype} not allowed)); } };

const upload = multer({ storage, fileFilter, limits: { fileSize: 10 * 1024 * 1024 }, // 10MB });

// Single file app.post('/upload', upload.single('file'), (req, res) => { res.json({ filename: req.file!.filename, size: req.file!.size }); });

// Multiple files app.post('/upload/multiple', upload.array('files', 10), (req, res) => { res.json({ count: (req.files as Express.Multer.File[]).length }); });

// Error handling app.use((err: Error, req: Request, res: Response, next: NextFunction) => { if (err instanceof multer.MulterError) { if (err.code === 'LIMIT_FILE_SIZE') return res.status(413).json({ error: 'File too large' }); return res.status(400).json({ error: err.message }); } if (err.message.includes('not allowed')) return res.status(415).json({ error: err.message }); next(err); });

Memory storage (for cloud forwarding)

const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 } });

app.post('/upload', upload.single('file'), async (req, res) => { // req.file.buffer contains the file — forward to S3 await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: req.file!.buffer, ContentType: req.file!.mimetype, })); });

Python (FastAPI)

from fastapi import UploadFile, File, HTTPException import aiofiles, uuid

ALLOWED_TYPES = {"image/jpeg", "image/png", "application/pdf"} MAX_SIZE = 10 * 1024 * 1024 # 10MB

@app.post("/upload") async def upload_file(file: UploadFile = File(...)): if file.content_type not in ALLOWED_TYPES: raise HTTPException(415, f"Type {file.content_type} not allowed")

content = await file.read()
if len(content) > MAX_SIZE:
    raise HTTPException(413, "File too large")

filename = f"{uuid.uuid4()}{Path(file.filename).suffix}"
async with aiofiles.open(f"uploads/{filename}", "wb") as f:
    await f.write(content)

return {"filename": filename, "size": len(content)}

Java (Spring Boot)

@PostMapping("/upload") public ResponseEntity<Map<String, String>> upload( @RequestParam("file") MultipartFile file) {

if (file.isEmpty()) throw new ResponseStatusException(BAD_REQUEST, "Empty file");
if (file.getSize() > 10_000_000) throw new ResponseStatusException(PAYLOAD_TOO_LARGE);

String ext = StringUtils.getFilenameExtension(file.getOriginalFilename());
String filename = UUID.randomUUID() + "." + ext;
Path dest = Path.of("uploads", filename);
file.transferTo(dest);

return ResponseEntity.ok(Map.of("filename", filename));

}

Spring config:

spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB

File Validation Beyond MIME

// Validate actual file content (magic bytes), not just extension import { fileTypeFromBuffer } from 'file-type';

const type = await fileTypeFromBuffer(req.file!.buffer); if (!type || !['image/jpeg', 'image/png'].includes(type.mime)) { return res.status(415).json({ error: 'Invalid file content' }); }

Anti-Patterns

Anti-Pattern Fix

Trust client MIME type only Validate magic bytes with file-type

Original filename as storage key Use UUID to prevent path traversal and collisions

No file size limit Always set limits.fileSize

Sync disk writes on upload Use streams or async writes

Storing uploads in app directory Use separate /uploads or cloud storage

No cleanup of temp files Implement lifecycle/cron cleanup

Production Checklist

  • File size limits configured

  • MIME type whitelist (validate magic bytes, not just extension)

  • UUID filenames (never use original filename for storage)

  • Multer error handler middleware

  • Virus scanning for user uploads (ClamAV)

  • Rate limiting on upload endpoints

  • Cleanup strategy for orphaned files

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

cron-scheduling

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

token-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

react-19

No summary provided by upstream source.

Repository SourceNeeds Review