Belajar Backstage - Persistence & Databases
Episode 12 of 23

Belajar Backstage - Persistence & Databases

Menata lapisan penyimpanan Backstage: perbandingan SQLite sebagai default pengembangan dengan PostgreSQL untuk produksi, peran Knex dan migrasi database, connection pooling dengan PgBouncer, serta konfigurasi cache Redis dan search index store untuk skala besar.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Di episode 11, kalian memperdalam catalog advanced: entity relations, ownership, catalog filters, hingga menjaga kualitas entity dengan validator di CI. Episode 12 ini bergeser dari bentuk data ke tempat penyimpanannya. Hampir semua plugin Backstage — catalog, scaffolder, auth, search — menulis ke database, dan begitu instance dipakai banyak orang, lapisan database justru menjadi titik yang paling sering menjadi sumber masalah. Memahami lapisan ini akan menyelamatkan kalian dari downtime yang tidak perlu.

Lapisan Penyimpanan Backstage

Backstage tidak mengunci satu jenis database tunggal. Setiap plugin backend memilih store yang sesuai dengan datanya:

  • Database relasional — untuk data yang butuh query terstruktur dan integritas: entity catalog, task scaffolder, sesi auth, dan sejenisnya.
  • Cache store — untuk data berumur pendek yang harus dibaca cepat dan berulang.
  • Search index store — untuk dokumen yang sudah di-parse dan siap di-query.

Ketiga lapisan ini dikonfigurasi lewat app-config.yaml, masing-masing di bawah key database, cache, dan search.

SQLite: Default Pengembangan

Saat baru melakukan bootstrap lewat npx @backstage/create-app@latest, kalian menemukan bahwa instance berjalan tanpa setup database tambahan. Itu karena Backstage menggunakan SQLite sebagai store default — zero-configuration, tersimpan sebagai file, dan sempurna untuk eksperimen di laptop.

Konfigurasi SQLite default
backend:
  database:
    client: better-sqlite3
    connection: ':memory:'

Kelebihan SQLite: tidak perlu server terpisah, portabel, dan cukup untuk development single-user. Kelemahannya jelas: tidak dirancang untuk beban bersamaan (concurrent writes), berbentuk single-file, dan tidak mendukung koneksi dari banyak instance sekaligus. Karena itu SQLite hanya layak untuk development dan test, bukan produksi.

PostgreSQL untuk Produksi

Saat kalian meluncurkan Backstage untuk tim sungguhan, PostgreSQL menjadi pilihan standar. Backstage mendukung Postgres sebagai database shared yang bisa diakses oleh banyak instance backend sekaligus — syarat mutlak untuk horizontal scaling.

Koneksi PostgreSQL di app-config
backend:
  database:
    client: pg
    connection:
      host: postgres.internal
      port: 5432
      user: backstage
      password: ${POSTGRES_PASSWORD}
      database: backstage

Perhatikan client: pg — itu memberi tahu Backstage bahwa koneksinya memakai driver PostgreSQL. Di belakang layar, koneksi ini dibuat lewat Knex, query builder yang dipakai semua plugin database Backstage.

SQLite vs PostgreSQL

AspekSQLitePostgreSQL
SetupZero-config, file lokalButuh server dan kredensial
ConcurrencyTerbatas, satu penulisBanyak pembaca dan penulis
Multi-instanceTidak cocokMendukung shared database
MigrasiDidukung KnexDidukung Knex
PenggunaanDevelopment dan testProduksi

Aturan praktisnya sederhana: mulai dengan SQLite agar cepat bereksperimen, lalu pindah ke PostgreSQL segera setelah environment produksi atau preview diinginkan. Banyak tim justru memakai Postgres sejak awal development untuk menghindari kejutan "berbeda antara laptop dan produksi".

Tip

Pindahlah ke PostgreSQL lebih awal daripada nanti. Semakin lama kalian menumpuk data di SQLite, semakin besar usaha migrasi di kemudian hari. Postgres lokal lewat Docker cukup untuk menyamakan perilaku dengan produksi.

Knex dan Migrasi Database

Knex adalah abstraksi database yang dipakai Backstage di hampir semua plugin. Dengan Knex, satu kode query bisa berjalan di SQLite maupun PostgreSQL tanpa diubah. Yang lebih penting, Knex menyediakan migrasi — skema database dikelola sebagai file migrasi yang versinya tercatat di tabel khusus. Lapisan database ini dibungkus menjadi service yang bisa diimpor dari @backstage/backend-defaults.

Saat kalian mengubah skema plugin atau menambahkan plugin baru, migrasi perlu dijalankan agar skema database sinkron:

Menjalankan migrasi database
yarn backstage-cli package schema migrate --package @internal/plugin-catalog

Perintah ini memastikan tabel yang dibutuhkan sebuah paket ada dan versinya sesuai. Dalam deployment production, migrasi biasanya dijalankan sebagai langkah sebelum aplikasi di-start — jangan pernah menaruh migrasi di dalam logika runtime yang hanya berjalan sekali.

Connection Pooling dengan PgBouncer

PostgreSQL membatasi jumlah koneksi aktif per instance. Masalahnya, Backstage membuka beberapa koneksi per plugin backend, dan jika kalian menjalankan banyak instance, jumlah koneksi bisa meledak. Di sinilah connection pooling berperan: pooler meminjamkan koneksi dari kumpulan kecil dan mengembalikannya setelah selesai.

PgBouncer adalah pooler paling umum dipakai bersama Backstage:

Konfigurasi PgBouncer mode transaction
[databases]
backstage = host=postgres.internal port=5432 dbname=backstage
 
[pgbouncer]
listen_port = 6432
pool_mode = transaction
max_client_conn = 1000

Dengan pool_mode = transaction, koneksi dipegang hanya selama satu transaksi berjalan, lalu dilepas kembali ke pool — pola yang cocok dengan workload Backstage yang pendek-pendek. Aplikasi lalu diarahkan ke port 6432 alih-alih langsung ke Postgres di 5432.

Cache Store: Redis

Sebagian data Backstage tidak butuh database relasional — cukup cache cepat yang bisa dibagikan antar instance. Default-nya adalah in-memory, yang bekerja untuk instance tunggal tetapi tidak konsisten begitu ada lebih dari satu instance. Untuk skala besar, Backstage mendukung Redis sebagai store cache:

Cache Redis di app-config
cache:
  backend:
    store: redis
    connection:
      url: redis://redis.internal:6379

Dengan Redis, cache bisa dibagikan antar instance sehingga hasil yang di-cache instance A juga berguna bagi instance B. Pastikan Redis dipasang di environment terpisah dari Postgres agar beban keduanya tidak saling mengganggu.

Search Index Store untuk Skala Besar

Fitur Search (yang akan kalian dalami di episode 16) membutuhkan index store. Secara default, index search disimpan di database utama — cukup untuk tim kecil. Saat jumlah entity dan dokumen membesar, kalian bisa mengalihkan search index ke engine khusus seperti Elasticsearch agar query tetap cepat tanpa membebani database utama.

Konfigurasi search engine dilakukan lewat key search di app-config.yaml. Keputusan besarnya: mulai dengan index di database, lalu pindahkan ke engine dedicated ketika volume dokumen dan kebutuhan query sudah melebihi kemampuan database utama.

Penutup

Episode 12 ini menata pondasi data Backstage: SQLite untuk development dan PostgreSQL untuk produksi, peran Knex dan migrasi untuk menjaga skema tetap konsisten, PgBouncer untuk memitigasi ledakan koneksi, Redis untuk cache yang bisa dibagikan antar instance, serta arah untuk memisahkan search index di skala besar.

Inti yang harus dibawa pulang:

  • SQLite hanya untuk development — produksi pakai PostgreSQL sebagai shared database.
  • Migrasi adalah langkah deployment — jalankan sebelum backend di-start, bukan di dalam runtime.
  • Pooling menyelamatkan koneksi — PgBouncer memisahkan beban koneksi dari Postgres itu sendiri.
  • Pisahkan cache dan index search — Redis dan search engine dedicated menjaga database utama tetap ringan.

Di episode 13 berikutnya, kalian masuk ke authorization: permission framework dan RBAC — bagaimana mengontrol siapa yang boleh melihat entity, menjalankan template, dan melakukan aksi tertentu. Data yang tersimpan rapi di episode ini akan dijaga dengan aturan akses yang tegas.

Belajar Backstage - Persistence & Databases | Belajar Backstage