Back to Blog
Building PixForge: A Self-Hosted Image Upload & Transformation API
backendnodejsdockers3minio

Building PixForge: A Self-Hosted Image Upload & Transformation API

How I built a full-stack image upload service with MinIO, Amazon S3, Docker, and Express.js — and what I learned about object storage along the way.

Why I Built PixForge

Image upload is one of those things that sounds simple but gets complicated fast. I wanted to build a service I actually understood end-to-end — not just copy-paste an SDK call.

PixForge is a backend API for image upload, transformation, and retrieval. It supports both MinIO (self-hosted) and Amazon S3 as storage backends, switchable via environment config.

Core Architecture

The stack is deliberately simple:

  • Express.js for the API server
  • Multer for multipart form handling
  • MinIO SDK / AWS SDK v3 for object storage
  • Docker for containerization and local MinIO
# Start PixForge with local MinIO
docker-compose up -d

Upload Flow

  1. Client sends multipart/form-data to /upload
  2. Multer buffers the file in memory
  3. The file is optionally resized/compressed using sharp
  4. The processed buffer is streamed to the configured bucket
  5. A signed URL is returned to the client
app.post('/upload', upload.single('image'), async (req, res) => {
  const buffer = await sharp(req.file.buffer)
    .resize({ width: 1200, withoutEnlargement: true })
    .webp({ quality: 85 })
    .toBuffer();

  const key = `${Date.now()}-${req.file.originalname}.webp`;
  await storageClient.putObject(bucket, key, buffer);

  const url = await storageClient.presignedGetObject(bucket, key, 3600);
  res.json({ url, key });
});

What I Learned

  • MinIO is genuinely S3-compatible — swapping the endpoint URL is enough to switch backends.
  • sharp is fast and produces significant size reductions (often 60–80% smaller).
  • Docker Compose makes local development with object storage feel effortless.
  • Signed URLs are the right pattern for temporary access — don't expose bucket directly.

Read the Full Article

This article is hosted on Hashnode. Read it here →

Related Posts

Running MongoDB in Docker: A Practical Guide for Backend Developers

Running MongoDB in Docker: A Practical Guide for Backend Developers

How to run MongoDB locally using Docker and Docker Compose, connect it to a Node.js app, and manage data with persistent volumes — no local MongoDB install needed.

backenddockermongodb+2 more
Read More
Sending Emails in Node.js with Nodemailer and SMTP

Sending Emails in Node.js with Nodemailer and SMTP

A practical guide to setting up transactional email in Node.js using Nodemailer, Gmail SMTP, and environment-based configuration — no third-party email service required.

backendnodejsemail+2 more
Read More

Designed & Built by Debanjan Das
© 2026. All rights reserved.