Arsitektur Upload File Skala Besar: Selamat Tinggal Server Lemot!
Sering overthinking karena fitur upload file bikin backend nangis? Pelajari cara efisien handle file besar menggunakan Presigned URL dan background job.

Daftar Isi
Share Article
Pendahuluan
Pernah nggak sih ngerasa aplikasi yang kita bangun tiba-tiba lemot banget pas ada user yang upload file gambar atau video ukuran jumbo?
Masalah ini lumayan bikin stres, apalagi kalau kita lagi semangat-semangatnya develop fitur yang butuh manajemen aset media yang stabil.
Seringkali, insting pertama kita adalah melempar file tersebut dari client langsung ke backend, padahal cara ini justru sering jadi sumber bottleneck yang mematikan performa server.
Konsep Dasar / Gambaran Arsitektur
Secara tradisional, file dikirim ke backend, disimpan sebentar di memori, lalu baru dilempar ke cloud storage.
Proses ini sangat memakan RAM server kita, apalagi kalau ukuran filenya bergiga-giga atau ada banyak request bersamaan.
Solusi elegan untuk masalah ini adalah menggunakan arsitektur Presigned URL.
Biar gampang, bayangkan backend kita itu satpam di sebuah gedung logistik. Daripada satpamnya yang harus nerima dan manggul barang gede-gede (yang pasti bikin antrian panjang), satpam cukup ngecek identitas dan ngasih "kunci loker sementara" (Presigned URL). Setelah itu, kurir (client) bisa langsung menaruh barangnya sendiri ke gudang utama (Cloud Storage) tanpa harus merepotkan satpam.
Step-by-Step Implementasi
Berikut adalah alur ideal untuk mengimplementasikan sistem upload direct ini:
- Request Presigned URL: Client mengirim API request ke backend untuk meminta izin melakukan upload.
- Generate URL: Backend memvalidasi request dan membuat Presigned URL (misal ke AWS S3 atau Google Cloud Storage) yang memiliki batas waktu kedaluwarsa.
- Direct Upload: Client mengunggah file langsung ke storage menggunakan URL tersebut. Beban backend menjadi nol di fase ini.
- Konfirmasi: Setelah upload selesai, client mengirim request konfirmasi ke backend bahwa file sudah aman tersimpan.
Berikut adalah contoh sederhana bagaimana backend kita men-generate Presigned URL:
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const s3Client = new S3Client({ region: "ap-southeast-1" });
export async function generateUploadUrl(fileName, fileType) {
const command = new PutObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key: `uploads/${Date.now()}-${fileName}`,
ContentType: fileType,
});
// URL ini hanya valid dan bisa digunakan upload selama 3600 detik (1 jam)
const uploadUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
return uploadUrl;
}Studi Kasus / Masalah Umum
Masalah klasik yang sering terjadi setelah upload selesai adalah memproses file tersebut, misalnya melakukan kompresi video menggunakan FFmpeg.
Banyak developer melakukan kesalahan fatal dengan menjalankan proses kompresi ini secara real-time saat request konfirmasi masuk. Akibatnya, client harus menunggu loading sangat lama sampai koneksi akhirnya timeout.
Solusi praktisnya adalah menggunakan Asynchronous Background Job atau sistem antrean (queue). Jadikan proses kompresi berjalan di belakang layar. Saat user selesai upload, langsung kembalikan respons sukses dengan status "Processing" layaknya sistem di YouTube.
Insight Personal
Dulu waktu awal-awal ngerjain project pakai ekosistem Laravel dan Next.js, urusan manajemen file berukuran besar ini sering bikin saya pusing sendiri.
Saya sempat berpikir:
"Ah, gampang, tinggal upload ke backend terus diproses di situ."
Ternyata mindset saya yang salah karena terlalu memaksakan semua beban perpindahan file dikerjakan oleh backend. Dengan mendelegasikan beban upload langsung ke storage lewat Presigned URL, arsitektur aplikasi ternyata terasa jauh lebih rapi, ringan, dan scalable.
Kesimpulan
Menangani file besar bukan berarti kita harus menyewa server backend mahal dengan spesifikasi yang kelewat tinggi.
Inti dari optimasi ini adalah: bypass beban unggahan langsung ke layanan pihak ketiga menggunakan Presigned URL, lalu kerjakan sisa proses beratnya secara asynchronous di belakang layar.
Dengan mengadopsi pola ini, aplikasi akan tetap responsif dan pengguna tidak perlu menatap layar loading yang tak kunjung usai.


