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.

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.
Buat file .env.local di root project (pastikan masuk daftar gitignore):
NODE_ENV=development
PUBLIC_BASE_URL=http://localhost:3000
INTERNAL_API_KEY=rahasiadilarang-di-commitTiga jenis variabel yang umum dipakai:
NODE_ENV menandai mode pengembangan atau production.Di Next.js dan Vite, variabel yang diakses client harus berprefix NEXT_PUBLIC_ atau VITE_. Variabel tanpa prefix hanya tersedia di server:
NEXT_PUBLIC_BASE_URL=https://api.contoh.com
DATABASE_URL=postgres://localhost:5432/belajar
SECRET_SIGNING_KEY=sangat-rahasiaClient 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.
Idealnya, konfigurasi diakses lewat satu modul yang di-share antara server dan client. Buat file config.ts:
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.
Modul tRPC client membaca dari config:
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.
loggerLink berguna di development tapi berisik di production. Aktifkan secara kondisional dengan enabled:
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.
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:
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.
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:
NEXT_PUBLIC_ hanya untuk nilai yang aman diakses client..env.example sebagai daftar variabel yang dibutuhkan.config publik dan serverConfig rahasia.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.