M
Michal
Guest
You're building an API endpoint that accepts images. You have three main approaches, and most devs pick the wrong one. Let's fix that.
Base64 converts binary data to text. Yes, it was useful for email attachments in 1995 when SMTP servers choked on binary data. Today? It's mostly a bad idea.
The reality: Base64 inflates your payload by ~33%. That 3MB image becomes 4MB. Your API parsing that JSON? It's now handling massive strings. Your database storing these strings? Enjoy the bloat.
When it's actually okay: Tiny icons or SVGs under 10KB embedded in CSS/HTML. That's it. If you're sending actual images this way, you're doing it wrong.
This is how HTML forms have sent files since forever. The catch? Everything that isn't a file becomes a string.
The problem: Your nice DTOs and validation decorators in NestJS? Useless. You're parsing strings and validating manually. That
When to use it: Simple uploads with minimal metadata. Profile picture update? Sure. Complex nested objects with files? Pain.
Upload files to one endpoint, get back IDs, then send those IDs with your JSON payload to another endpoint.
The tradeoff: Yes, orphaned files. Write a cleanup job that runs every hour and deletes uploads older than 24 hours without associations. It's 20 lines of code, not rocket science.
Why this wins:
Stop overthinking this. For 90% of apps, use separate endpoints. For simple forms with a single file, use multipart. Never use base64 for actual files unless you enjoy angry users and slow APIs.
And please, implement proper file validation. Check MIME types, file sizes, and actually validate the file content. Users will upload anything.
Got a different approach? Think I'm wrong about base64? Running into edge cases I didn't cover? Drop a comment. And if you're still sending 10MB PNGs as base64 strings in 2025, we need to talk.
Continue reading...
1. Base64 Encoding (The Lazy Way)
Base64 converts binary data to text. Yes, it was useful for email attachments in 1995 when SMTP servers choked on binary data. Today? It's mostly a bad idea.
The reality: Base64 inflates your payload by ~33%. That 3MB image becomes 4MB. Your API parsing that JSON? It's now handling massive strings. Your database storing these strings? Enjoy the bloat.
When it's actually okay: Tiny icons or SVGs under 10KB embedded in CSS/HTML. That's it. If you're sending actual images this way, you're doing it wrong.
2. Multipart/Form-Data (The Standard Way)
This is how HTML forms have sent files since forever. The catch? Everything that isn't a file becomes a string.
Code:
// What you send
formData.append('file', imageFile);
formData.append('metadata', JSON.stringify({ title: 'My Image', tags: ['nature'] }));
The problem: Your nice DTOs and validation decorators in NestJS? Useless. You're parsing strings and validating manually. That
metadata
field? You're JSON.parse()
-ing it and praying it's valid.When to use it: Simple uploads with minimal metadata. Profile picture update? Sure. Complex nested objects with files? Pain.
3. Separate Endpoints (The Clean Way)
Upload files to one endpoint, get back IDs, then send those IDs with your JSON payload to another endpoint.
Code:
// Step 1: Upload image
POST /api/uploads
Response: { id: "abc123", url: "https://..." }
// Step 2: Create resource with image reference
POST /api/posts
Body: { title: "My Post", imageId: "abc123", ... }
The tradeoff: Yes, orphaned files. Write a cleanup job that runs every hour and deletes uploads older than 24 hours without associations. It's 20 lines of code, not rocket science.
Why this wins:
- Clean separation of concerns
- DTOs work normally
- Better caching strategies
- Resumable uploads become possible
- Can optimize file handling separately (CDN, processing queues)
The Production Reality
Stop overthinking this. For 90% of apps, use separate endpoints. For simple forms with a single file, use multipart. Never use base64 for actual files unless you enjoy angry users and slow APIs.
And please, implement proper file validation. Check MIME types, file sizes, and actually validate the file content. Users will upload anything.
Questions?
Got a different approach? Think I'm wrong about base64? Running into edge cases I didn't cover? Drop a comment. And if you're still sending 10MB PNGs as base64 strings in 2025, we need to talk.
Continue reading...