Langsung ke konten
Docker untuk Database Development: Setup PostgreSQL Lokal dalam 5 Menit Tanpa Instal Manual
Kembali ke Blog
Database·6 menit baca·

Docker untuk Database Development: Setup PostgreSQL Lokal dalam 5 Menit Tanpa Instal Manual

Cara setup PostgreSQL lokal pakai Docker untuk development: satu command, data persisten lewat volume, tanpa instal manual dan tanpa merusak database utama di laptop Anda.

TH
Tomi Hartanto·Senior Software Engineer

Minggu lalu seorang junior di tim saya menghabiskan hampir satu hari mencoba downgrade PostgreSQL 16 ke 14 di laptopnya, karena proyek klien masih pakai versi itu. Dia instal paket, bentrok dengan instalasi lama, akhirnya reinstall. Padahal masalah ini selesai dalam 5 menit kalau dia pakai Docker. Setiap proyek bisa punya PostgreSQL versi berbeda, jalan berdampingan, dan tidak menyentuh sistem operasi sama sekali.

Saya sudah lebih dari lima tahun tidak menginstal PostgreSQL secara native di mesin development. Semua database lokal saya hidup di container. Di artikel ini saya tuliskan setup persis yang saya pakai — bukan teori, tapi docker-compose.yml yang benar-benar saya salin-tempel antar proyek.

Kenapa Docker untuk Database Development?

Tiga alasan praktis yang saya rasakan sendiri:

  1. Versi berbeda per proyek tanpa drama. Proyek A pakai PostgreSQL 14, proyek B pakai 16. Dengan Docker, keduanya jalan bersamaan di port berbeda.
  2. Reset total dalam hitungan detik. Mau eksperimen dengan migrasi rusak? Hapus volume, jalankan ulang, database bersih seperti baru.
  3. Onboarding tim lebih cepat. Anggota baru cukup docker compose up — tidak ada dokumen "cara instal Postgres di Mac M1" yang selalu outdated.

Ilustrasi developer menjalankan beberapa container PostgreSQL versi berbeda berdampingan di laptop

Satu kekhawatiran yang sering muncul: apakah PostgreSQL di Docker lambat untuk development? Untuk kebutuhan development lokal, jawabannya: Anda tidak akan merasakan bedanya. Pertanyaan ini sudah lama dibahas, termasuk benchmark PostgreSQL Performance on Docker yang menunjukkan overhead Docker untuk beban database relatif kecil. Untuk produksi memang ada nuansa lain (I/O dan tuning), tapi untuk lokal? Tidak relevan.

Setup 5 Menit: docker-compose.yml

Buat file docker-compose.yml di root proyek:

services:
  db:
    image: postgres:16-alpine
    container_name: myapp-db
    environment:
      POSTGRES_USER: myapp
      POSTGRES_PASSWORD: myapp_dev
      POSTGRES_DB: myapp
    ports:
      - "5432:5432"
    volumes:
      - myapp_pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myapp"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  myapp_pgdata:

Lalu jalankan:

docker compose up -d

Selesai. PostgreSQL 16 jalan di localhost:5432. Kalau port 5432 sudah terpakai (misal Anda masih punya instalasi native), ganti mapping-nya jadi "5433:5432" dan connect ke port 5433.

Beberapa keputusan di file ini yang saya pertahankan di semua proyek:

  • Image alpine — lebih kecil (~80MB vs ~240MB), cukup untuk development. Untuk production-like testing, saya ganti ke image non-alpine karena extension tertentu tidak tersedia di alpine.
  • Named volume, bukan bind mount — performance I/O lebih stabil, khususnya di macOS dan Windows.
  • Healthcheck — penting supaya service lain (API Anda) bisa menunggu dengan depends_on: db: condition: service_healthy, bukan nebak-nebak pakai sleep 10.

Koneksi dari Aplikasi

Untuk Prisma, .env saya biasanya begini:

DATABASE_URL="postgresql://myapp:myapp_dev@localhost:5432/myapp?schema=public"

Satu jebakan yang sering menangkap orang: dari dalam jaringan Docker Compose (kalau aplikasi Anda juga dijalankan sebagai container), hostname-nya adalah nama service (db), bukan localhost. Ini pertanyaan klasik di Stack Overflow — "mengapa saya tidak bisa connect ke PostgreSQL di container dari luar?" — dan jawabannya hampir selalu: port tidak di-publish via ports:, atau Anda memakai localhost dari dalam container lain.

Yang Saya Lakukan Sebelum Migrasi Berbahaya

Kekuatan terbesar setup ini bukan "cepat jalan", tapi cepat reset dan snapshot.

Sebelum menjalankan migrasi besar atau eksperimen skema, saya snapshot dulu:

docker exec myapp-db pg_dump -U myapp myapp > backup-sebelum-migrasi.sql

Kalau migrasi meledak, restore:

cat backup-sebelum-migrasi.sql | docker exec -i myapp-db psql -U myapp myapp

Atau kalau benar-benar mau mulai dari nol:

docker compose down -v   # -v menghapus volume, HATI-HATI: data hilang
docker compose up -d

Flag -v itu pedang bermata dua. Untuk development itu fitur (reset bersih); pastikan Anda tidak menjalankannya sambil lupa bahwa di volume itu ada data eksperimen yang masih Anda butuhkan. Perintah pg_dump dan ekspor hasil query dari container ke mesin lokal juga sering ditanyakan di Stack Overflow — polanya sama, docker exec + redirect stdout.

Ilustrasi backup database PostgreSQL dari container ke file SQL di komputer lokal

Seed Data yang Tidak Bikin Malu

Setiap proyek saya tambahkan seed script yang bisa dijalankan ulang kapan saja. Dengan container, caranya simpel:

docker exec -i myapp-db psql -U myapp myapp < ./scripts/seed.sql

Atau mount folder ./scripts sebagai docker-entrypoint-initdb.d — semua .sql dan .sh di sana dijalankan otomatis saat volume masih kosong:

    volumes:
      - myapp_pgdata:/var/lib/postgresql/data
      - ./scripts:/docker-entrypoint-initdb.d

Catatan penting: init script hanya jalan saat database baru dibuat. Kalau volume sudah ada data, file itu diabaikan. Ini sering bikin bingung — "kok seed saya tidak jalan?" — jawabannya: jalankan docker compose down -v dulu.

Kalau Ada Docker, Apakah Tools Lain Masih Perlu?

Jujur: tergantung kasus. Beberapa catatan trade-off dari pengalaman saya:

  • Docker Desktop di macOS cukup berat (RAM). Kalau laptop Anda 8GB dan menjalankan banyak service, pertimbangkan jalankan hanya db yang perlu, bukan seluruh stack.
  • Untuk testing integrasi di CI, saya tetap pakai pola yang sama — service postgres di GitHub Actions pada dasarnya adalah pendekatan serupa.
  • Untuk produksi, Docker single-container bukan solusi HA. Kalau butuh klaster dan failover, tools seperti Spilo dari Zalando memang ada untuk itu — tapi itu topik berbeda dari development lokal. Ada juga project seperti pgautoupgrade untuk auto-upgrade versi major saat container restart, yang menarik kalau Anda malas mengurus dump-restore saat ganti versi — saya sendiri masih lebih suka upgrade eksplisit dengan dump/restore supaya tahu persis apa yang terjadi.

Setelah database lokal Anda berjalan rapi, langkah natural berikutnya adalah memastikan data uji Anda memang merepresentasikan data nyata — karena query yang lambat jarang kelihatan di tabel berisi 100 baris. Kalau Anda sudah sampai tahap itu, artikel saya tentang membaca EXPLAIN ANALYZE di PostgreSQL akan langsung terpakai. Dan kalau aplikasi Anda SaaS multi-tenant, keputusan soft delete vs hard delete sebaiknya diputuskan sebelum migrasi pertama ditulis, bukan setelahnya.

Takeaway

Salin docker-compose.yml di atas ke proyek Anda sekarang, jalankan docker compose up -d, dan Anda punya PostgreSQL 16 lokal dengan data persisten dalam waktu kurang dari lima menit. Tiga kebiasaan yang saya sarankan dibentuk sejak hari pertama: selalu snapshot dengan pg_dump sebelum migrasi besar, taruh seed di docker-entrypoint-initdb.d supaya reset itu murah, dan beri healthcheck supaya service lain tidak berlomba dengan startup database. Lima menit setup ini akan menghemat hari-hari Anda di kemudian waktu.

Sumber

TH

Tomi Hartanto

Senior Software Engineer

Backend developer dengan 8+ tahun pengalaman membangun sistem scalable. Menulis tentang arsitektur backend, database, dan DevOps.