Belajar tRPC - Konfigurasi tRPC dan Environment Variables
Episode 7 of 19

Belajar tRPC - Konfigurasi tRPC dan Environment Variables

Episode ini merapikan sisi konfigurasi: environment variables untuk base URL, API keys, dan mode pengembangan, struktur konfigurasi tRPC yang di-share antara client dan server, serta penerapan conditional loggerLink antara development dan production.

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

Pendahuluan

Kode yang baik tidak pernah menyimpan konfigurasi secara hardcoded. Base URL, API keys, dan mode pengembangan harus hidup di environment variables, dan tRPC tidak terkecuali. Episode 7 membahas cara mengelola konfigurasi tersebut secara rapi: mengatur environment variables, menyusun konfigurasi shared antara client dan server, serta menerapkan loggerLink secara kondisional.

Setelah episode ini, project kalian siap berpindah antar environment — lokal, staging, dan production — tanpa mengubah satu baris kode aplikasi.

Mengatur Environment Variables

File .env dan Variabel Kunci

Buat file .env.local di root project (pastikan masuk daftar gitignore):

Isi file .env.local
NODE_ENV=development
PUBLIC_BASE_URL=http://localhost:3000
INTERNAL_API_KEY=rahasiadilarang-di-commit

Tiga jenis variabel yang umum dipakai:

  • NODE_ENV menandai mode pengembangan atau production.
  • Base URL publik yang akan dipakai client.
  • Secret seperti API key yang hanya boleh dibaca di sisi server.

Konvensi Prefix PUBLIC

Di Next.js dan Vite, variabel yang diakses client harus berprefix NEXT_PUBLIC_ atau VITE_. Variabel tanpa prefix hanya tersedia di server:

Prefix untuk variabel publik
NEXT_PUBLIC_BASE_URL=https://api.contoh.com
DATABASE_URL=postgres://localhost:5432/belajar
SECRET_SIGNING_KEY=sangat-rahasia

Client bisa membaca NEXT_PUBLIC_BASE_URL, tetapi DATABASE_URL dan secret tetap aman di server. Tuliskan seluruh variabel yang dibutuhkan di .env.example agar anggota tim tahu apa yang harus diisi — jangan pernah mengisi nilai rahasia di file contoh.

Struktur Konfigurasi tRPC Shared

Satu Modul Konfigurasi

Idealnya, konfigurasi diakses lewat satu modul yang di-share antara server dan client. Buat file config.ts:

Modul konfigurasi shared
const publicBaseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000";
 
export const config = {
  isDev: process.env.NODE_ENV === "development",
  publicBaseUrl,
  trpcUrl: `${publicBaseUrl}/api/trpc`,
  wsUrl: process.env.NEXT_PUBLIC_WS_URL ?? "ws://localhost:3000/trpc",
};
 
export const serverConfig = {
  internalApiKey: process.env.INTERNAL_API_KEY ?? "",
  databaseUrl: process.env.DATABASE_URL ?? "",
};
  • config aman diakses di mana saja, termasuk client, karena hanya berisi nilai publik.
  • serverConfig hanya dipakai di server — memuat secret yang tidak boleh bocor ke bundle client.

Dengan pola ini, perubahan base URL cukup dilakukan di satu file. Client dan server memakai nilai yang sama sehingga tidak ada kemungkinan URL tidak sinkron.

Memakai Konfigurasi di Client

Modul tRPC client membaca dari config:

Client memakai konfigurasi
import { createTRPCReact } from "@trpc/react-query";
import { httpBatchLink } from "@trpc/client";
import { config } from "@/lib/config";
 
export const trpc = createTRPCReact<AppRouter>();
 
export const trpcClient = trpc.createClient({
  links: [
    httpBatchLink({
      url: config.trpcUrl,
    }),
  ],
});

config.trpcUrl menurunkan endpoint dari NEXT_PUBLIC_BASE_URL, sehingga mengganti domain hanya dengan mengubah environment variable.

Aktifkan Logger Hanya di Development

loggerLink berguna di development tapi berisik di production. Aktifkan secara kondisional dengan enabled:

Conditional loggerLink
import { loggerLink } from "@trpc/client";
import { config } from "@/lib/config";
 
export const trpcClient = trpc.createClient({
  links: [
    loggerLink({
      enabled: () => config.isDev,
    }),
    httpBatchLink({
      url: config.trpcUrl,
    }),
  ],
});

loggerLink({ enabled: () => config.isDev }) hanya mencatat request saat NODE_ENV bernilai development. Di production, link ini tidak mengeluarkan log sama sekali — menghemat bandwidth dan menghindari kebocoran informasi lewat log.

Logger di Server

Di sisi server, logging bisa ditambahkan lewat middleware — persis pola logger dari episode 6. Dengan menggabungkan config.isDev, middleware bisa mencatat detail lengkap di development dan hanya error di production:

Middleware logger server
const logger = t.middleware(async ({ path, type, next }) => {
  const mulai = Date.now();
  const hasil = await next();
  if (config.isDev || !hasil.ok) {
    console.log(`${type} ${path} selesai ${Date.now() - mulai}ms`);
  }
  return hasil;
});

config.isDev || !hasil.ok membuat produksi hanya mencatat kegagalan, sementara development mencatat semuanya.

Warning

Jangan pernah mengakses serverConfig atau secret di dalam kode yang diimport client. Variabel tanpa prefix NEXT_PUBLIC_ tidak tersedia di browser — akses dari client akan menghasilkan undefined dan bisa bocor lewat bundling jika diimport langsung.

Penutup

Episode 7 merapikan konfigurasi: environment variables menjadi satu-satunya sumber kebenaran, modul konfigurasi shared menjaga client dan server tetap sinkron, dan loggerLink diaktifkan secara kondisional agar development nyaman tanpa mengotori production.

Inti yang harus dibawa pulang:

  • Simpan base URL, API keys, dan mode di environment variables.
  • Gunakan prefix NEXT_PUBLIC_ hanya untuk nilai yang aman diakses client.
  • Sediakan .env.example sebagai daftar variabel yang dibutuhkan.
  • Pisahkan config publik dan serverConfig rahasia.
  • Satu modul konfigurasi mencegah client dan server tidak sinkron.
  • loggerLink({ enabled: () => isDev }) untuk logging kondisional.

Di episode 8 selanjutnya kita akan membahas state management & data fetching patterns — pola query, mutation, invalidate, dan optimistic updates, integrasi @tanstack/react-query yang modern, serta teknik caching, refetch, dan penanganan stale data.