SQLite memenuhi kebutuhan aplikasi kecil dengan sangat baik, tetapi begitu banyak proses harus membaca dan menulis data yang sama secara serentak, kita membutuhkan database client-server. PostgreSQL adalah pilihan open-source paling populer di kelas itu, dan driver resminya untuk Node.js adalah package pg. Chapter ini membahas cara menginstal pg, membuka koneksi dengan Client maupun Pool, menyusun connection string, mengelola kredensial dengan berkas .env, serta mengaktifkan TLS untuk koneksi produksi.

Menginstal Driver pg #

Driver pg dipelihara di repositori node-postgres dan dipasang seperti package npm lainnya:

bash
npm install pg

Package ini mendukung CommonJS maupun ES Modules. Pada berkas .mjs kita mengimpor default export lalu mengambil class yang dibutuhkan, karena pg ditulis dengan gaya CommonJS:

js Mengimpor pg pada ES Modules
import pg from 'pg';

const { Client, Pool } = pg;

Client — Satu Koneksi Sesi Tunggal #

Class Client mewakili satu koneksi TCP ke server PostgreSQL. Siklus hidupnya persis seperti lima tahap pada Chapter Konsep Database Driver — sambungkan, kirim query, olah hasil, akhirnya putuskan:

js Koneksi tunggal dengan Client
import pg from 'pg';

const { Client } = pg;

const client = new Client({
  connectionString: process.env.DATABASE_URL,
});

await client.connect();

const hasil = await client.query(
  'SELECT id, judul FROM tugas WHERE selesai = $1',
  [false]
);

console.log(hasil.rows);

await client.end();

Method client.query() menerima teks SQL beserta array parameter. Angka bertanda dolar — $1, $2 — adalah placeholder yang diisi secara berurutan dari array; 'Belajar' tidak pernah dirangkai ke string SQL, melainkan dikirim terpisah lewat protokol. Hasil query hadir dalam object dengan beberapa field penting: rows berisi array of object hasil query, rowCount berisi jumlah baris, dan command berisi jenis statement yang dijalankan. Karena setiap panggilan menembus jaringan, seluruh operasinya asynchronous dan harus di-await.

Pool — Koneksi Siap Pakai #

Membuka koneksi baru untuk setiap query itu mahal: ada jabat tangan TCP, autentikasi, lalu penyiapan sesi di sisi server. Class Pool menyimpan sejumlah koneksi yang tetap terbuka dan meminjamkannya bergantian — pool.query() mengambil koneksi nganggur, memakainya, lalu mengembalikannya:

js Koneksi dengan Pool
import pg from 'pg';

const { Pool } = pg;

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
});

const hasil = await pool.query('SELECT NOW() AS waktu_server');
console.log(hasil.rows);

await pool.end();

Opsi max membatasi jumlah koneksi maksimum yang dibuat pool. Pembahasan mendalam — kenapa pool penting, bagaimana antrian pemohon bekerja, dan opsi-opsi lainnya — menjadi panggung utama Chapter Connection Pooling; untuk sekarang, cukup kenali bentuknya karena berkas contoh lengkap di bawah memakai Pool.

Kredensial dengan Berkas .env #

Connection string lengkap berisi pengguna dan kata sandi — dua hal yang tidak boleh tertulis di kode sumber. Solusinya adalah menyimpan connection string sebagai variabel lingkungan, lalu memuatnya saat aplikasi berjalan. Berkas .env berisi pasangan kunci-nilai:

text Isi berkas .env
DATABASE_URL=postgresql://pengguna:YOUR_DATABASE_PASSWORD@localhost:5432/tugasdb

Node.js dapat memuat berkas tersebut secara bawaan lewat flag --env-file, yang didokumentasikan bersama opsi CLI lainnya di nodejs.org/api/cli.html :

bash
node --env-file=.env aplikasi.mjs

Dengan cara ini, kode hanya membaca process.env.DATABASE_URL dan tidak pernah mengetahui kata sandinya; berkas .env sendiri didaftarkan ke .gitignore agar tidak ikut terkirim ke repositori.

TLS untuk Koneksi Produksi #

Server PostgreSQL di jaringan lokal biasanya menerima koneksi tanpa enkripsi. Layanan database terkelola di internet umumnya mensyaratkan TLS agar data yang lewat jaringan publik tidak dapat dibaca pihak lain. Ada dua cara mengaktifkannya: menambahkan parameter sslmode pada connection string (...tugasdb?sslmode=require) atau menyetel opsi ssl pada konstruktor:

js Opsi TLS pada Pool
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: true },
});

Opsi rejectUnauthorized: true meminta pg memverifikasi sertifikat server — pengaturan yang tepat untuk produksi. Nilai ssl: true hanya mengaktifkan enkripsi tanpa verifikasi dan sebaiknya dipakai hanya saat bereksperimen.

Berkas Contoh Lengkap #

Berkas berikut merangkai seluruh materi chapter menjadi satu program utuh: membuat tabel, menyisipkan data dengan parameter terikat, lalu membacanya kembali. Jalankan di komputer yang memiliki server PostgreSQL beserta berkas .env yang berisi DATABASE_URL:

js
// contoh-pg.mjs — butuh server PostgreSQL berjalan (tidak diuji di Course ini).
// Persiapan:
//   1. npm install pg
//   2. Buat berkas .env (lihat Chapter) lalu jalankan:
//      node --env-file=.env contoh-pg.mjs
import pg from 'pg';

const { Pool } = pg;

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
});

async function main() {
  // Buat tabel sekali di awal (aman diulang berkat IF NOT EXISTS).
  await pool.query(`
    CREATE TABLE IF NOT EXISTS tugas (
      id SERIAL PRIMARY KEY,
      judul TEXT NOT NULL,
      selesai BOOLEAN NOT NULL DEFAULT false
    )
  `);

  // Sisipkan data dengan parameter terikat ($1, $2, ...).
  const sisip = await pool.query(
    'INSERT INTO tugas (judul, selesai) VALUES ($1, $2) RETURNING *',
    ['Belajar PostgreSQL', false]
  );
  console.log('Tugas baru:', sisip.rows);

  // Baca data — hasil ada di property rows.
  const daftar = await pool.query('SELECT * FROM tugas ORDER BY id');
  console.log('Daftar tugas:', daftar.rows);

  await pool.end();
}

main().catch((error) => {
  console.error('Koneksi atau query gagal:', error.message);
  process.exit(1);
});

Beberapa hal baru di berkas ini pantas diperhatikan. Tipe SERIAL PRIMARY KEY membuat PostgreSQL menomori baris baru secara otomatis — padanan langsung dari INTEGER PRIMARY KEY di SQLite. Klausal RETURNING * meminta baris yang baru disisipkan dikirim balik, sehingga kita langsung memperoleh id yang diberikan server tanpa query tambahan. Terakhir, blok .catch() pada main() memastikan galat koneksi atau query dilaporkan sebagai pesan singkat dan proses keluar dengan kode gagal, bukan uncaught exception dengan stack trace panjang.

PostgreSQL kini terhubung: tabel dibuat, data mengalir, hasil terbaca sebagai object JavaScript. Dunia database tidak berhenti di satu produk — MySQL, tetangga yang sama populernya, memiliki driver dengan selera API yang sedikit berbeda, dan membandingkan keduanya justru cara tercepat memperdalam pemahaman. Kita ke sana pada Chapter Koneksi MySQL dengan mysql2.