← Back to list

End-to-End Type Safety di Next.js dengan tRPC & TanStack Query.

Kenapa Anda Harus Menggunakan tRPC di Proyek Next.js Berikutnya?

Muhammad Faiz Annabil · 2026-03-25 06:33 · 0 claps · 4.1 min read
#nextjs #full-stack-development #trpc #tanstack-query #react-query
Open on Medium ↗
Wiki topics: SAF · Safety & Alignment 🌐 · Web Development

End-to-End Type Safety di Next.js dengan tRPC & TanStack Query.

Seringkali saat membangun aplikasi Next.js, kita terjebak dalam siklus: membuat API route, menentukan tipe data (interface) di backend, lalu pindah ke frontend, menulis fungsi fetch, dan membuat ulang interface yang sama agar tidak error.

Tapi apa masalahnya?

Masalahnya adalah jika kita perlu mengubah backend, frontend tidak tahu kalau backend berubah dan aplikasi bisa crash saat digunakan user.

Di sinilah tRPC masuk sebagai solusi. tRPC memungkinkan kita untuk berbagi types antara server dan client secara langsung tanpa perlu proses code generation yang rumit.

Namun, tRPC tidak bekerja sendirian. Ia bisa dikolaborasikan dengan TanStack Query, sebuah library untuk asynchronous state management yang sangat versatile dalam fullstack development. Jika tRPC adalah “kabel” yang menghubungkan kedua sisi, maka TanStack Query adalah “otak” yang mengelola data fetching, caching, dan synchronization di sisi client.

Salah satu alasan utama mengapa tRPC disukai adalah karena ia memecahkan masalah klasik fullstack development di mana kita sering menebak-nebak struktur JSON dari API. Dengan tRPC, hal itu tidak lagi terjadi karena adanya fitur Intellisense yang memberikan autocomplete dari semua procedure di server tepat saat Anda mengetik API di sisi client.

Selain itu, ada juga Instant Feedback. Hal ini membuat frontend langsung mengetahui perubahan pada database schema atau Zod validation di backend. TypeScript akan langsung memberikan indikasi error pada kode frontend Anda, sehingga bug dapat ditangkap seketika saat proses development tanpa harus menunggu runtime.

Setup Project

Sekarang mari kita coba mengimplementasikan TanStack Query dan tRPC sederhana dengan project structure seperti ini:

├── src/
│   ├── app/
│   │   ├── _components/
│   │   │    └── QueryClientProviders.tsx # Provider untuk tRPC & TanStack Query
│   │   └── api/
│   │       └── trpc/
│   │           └── [trpc]/
│   │               └── route.ts # HTTP Handler (Menjadikan procedures sebagai API)
│   ├── server/
│   │   ├── trpc.ts            # Inisialisasi tRPC (Router & Public Procedure)
│   │   ├── routers/           # Kumpulan API Procedures (Router Utama)
│   │   │    └── [nama_modul]/ # Folder per modul (contoh: user, product)
│   │   │        ├── router.ts # Definisi endpoint/procedure untuk modul ini
│   │   │        ├── [nama_modul].actions.ts # Logika bisnis (Service layer)
│   │   │        └── [nama_modul].repository.ts # Query database (Data access layer)
│   │   └── index.ts           # Root Router (Menggabungkan semua modul)
│   └── client/
│       ├── trpc.ts            # Konfigurasi tRPC client (React Query hooks)
│       └── index.ts           # Entry point untuk penggunaan di komponen
  1. Init tRPC Server, pada **src/server/trpc.ts**tulis code dibawah ini untuk menginisiasi tRPC Server
import { initTRPC } from '@trpc/server';

const t = initTRPC.create();

export const router = t.router;
export const publicProcedure = t.procedure;
  1. Definisi Router Utama, dilanjutkan pada **src/server/index.ts **dengan code seperti ini, yang akan membuat server & mendefinisikan procedures yang sudah dibuat
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { router } from './trpc';

// mendefinisikan router utama yang menggabungkan semua router yang ada
const appRouter = router({
    example:  exampleRouter // contoh router dengan app route nya
});

// membuat server HTTP dengan router yang sudah didefinisikan
const server = createHTTPServer({
  router: appRouter,
});

// export type dari appRouter untuk digunakan di client
export type AppRouter = typeof appRouter;
  1. Inisiasi Client, Untuk menginisiasi sisi client, kita perlu membuat dua file utama di folder **src/client/**:
  • **src/client/index.ts **, berfungsi mengatur QueryClient dan konfigurasi httpBatchLink.
import { AppRouter } from '@/server';
import { createTRPCClient, httpBatchLink } from '@trpc/client';

// Memberi tahu `trpc` tentang prosedur yang tersedia di server dan tipe input/output mereka.
const trpc = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: '/api/trpc',
    }),
  ],
});
  • **src/client/trpc.ts , *menghubungkan type dari server ke frontend* menggunakan createTRPCReact.
"use client";

import type { AppRouter } from "@/server";
import { createTRPCReact } from "@trpc/react-query";

export const trpc = createTRPCReact<AppRouter>();

Setelah menginisiasi tRPC client, kita juga perlu mengonfigurasi API routing di dalam folder **app/api/trpc/[trpc]/route.ts untuk memastikan procedures kita dapat diakses sebagai endpoint API** oleh aplikasi.

  • **app/api/trpc/[trpc]/route.ts**
import { appRouter } from "@/server";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";

const handler = (req: Request) =>
  fetchRequestHandler({
    endpoint: "/api/trpc",
    req,
    router: appRouter,
    createContext: () => ({}),
  });

export { handler as GET, handler as POST };

Terakhir kita perlu setup providersnya untuk diakses aplikasi pada **src/app/_components/QueryClientProviders.tsx yang kemudian akan di gunakan di `layout.tsx`**

  • **src/app/_components/QueryClientProviders.tsx**
"use client";

import { queryClient, trpcClient } from "@/client";
import { trpc } from "@/client/trpc";
import { QueryClientProvider } from "@tanstack/react-query";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <trpc.Provider client={trpcClient} queryClient={queryClient}>
        {children}
      </trpc.Provider>
    </QueryClientProvider>
  );
}

/* di layout.tsx tinggal buat seperti ini
   <html lang="en">
     <body
       className={`${geistSans.variable} ${geistMono.variable} antialiased`}
     >
      <Providers>
         {children}
      </Providers>
     </body>
   </html>
*/

Demo

Setelah semua setup tadi, kita sudah siap untuk mulai membuat API dengan tRPC & Tanstack Query, mari kita coba buat module hello-world sederhana sesuai struktur project tadi.

buat module **src/server/router/hello-world/ dengan file `router.ts** danhello-world.actions.ts` didalamnya

  1. **hello-world.actions.ts**
export const helloWorldAction = async () => {
    return 'Hello World from tRPC & Tanstack Query!';
}
  1. **router.ts **, Selanjutnya, buat helloWorldRouter untuk mengelompokkan API berdasarkan modulnya.
import { publicProcedure, router } from '../../trpc';
import { helloWorldAction } from './hello-world.actions';

export const helloWorldRouter = router({
    hello: publicProcedure.query(helloWorldAction),
});
  1. Pada **src/server/index.ts**
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { helloWorldRouter } from './router/hello-world/routers';
import { router } from './trpc';

export const appRouter = router({
  /*
  tambahkan ini untuk membuat procedures helloWorld 
  yang nanti bisa digunakan di frontend
  */
  helloWorld: helloWorldRouter
});

export const server = createHTTPServer({
  router: appRouter,
});

server.listen(3000);

export type AppRouter = typeof appRouter;

Terakhir di frontend kita bisa menggunakan procedure **helloWorld **tadi dengan seperti ini

"use client";

import { trpc } from "@/client/trpc";

export default function Home() {
  const { data, isLoading } = trpc.helloWorld.hello.useQuery();

  if (isLoading) return <div>Loading...</div>;

  return <div>{data}</div>;
}

Page tadi akan tampil seperti ini.

Example page

Example page

Pada akhirnya, menggunakan tRPC dan TanStack Query di dalam Next.js bukan sekadar tentang mengikuti tren tech stack terbaru. Ini adalah salah satu opsi solusi untuk masalah klasik yang sering kita hadapi yaitu sinkronisasi manual antara client dan server yang melelahkan dan rawan error.


메타데이터
post_id
511f2943afe8
slug
end-to-end-type-safety-di-next-js-dengan-trpc-tanstack-query-511f2943afe8
url
https://medium.com/@faizannabil877/end-to-end-type-safety-di-next-js-dengan-trpc-tanstack-query-511f2943afe8
canonical_url
https://medium.com/@faizannabil877/end-to-end-type-safety-di-next-js-dengan-trpc-tanstack-query-511f2943afe8
author_url
https://medium.com/@faizannabil877
status
ok
fetched_at
2026-06-21 19:25:17