Episode 19 mengoptimalkan performa GraphQL: analisis query dan identifikasi bottleneck, index database, strategi caching dan ETag, Automatic Persisted Queries, field-level caching dengan memoization, batching dan DataLoader optimization, hingga monitoring performa query.

GraphQL memberi fleksibilitas besar bagi client — dan fleksibilitas itu sering menjadi biang performa buruk. Episode 19 membahas optimasi performa GraphQL secara sistematis: menemukan bottleneck, mempercepat query, dan mengukur hasilnya.
Kita akan mulai dari analisis query, lalu membangun lapisan caching, Automatic Persisted Queries, field-level caching, optimasi batching, dan menutup dengan strategi monitoring performa.
Sebelum mengoptimalkan, ukur dulu. Metrik kunci untuk setiap query:
Alat termudah: plugin tracing Apollo untuk mencatat durasi tiap resolver. Pola bottleneck yang paling umum adalah N+1 (episode 9) dan resolver yang melakukan pekerjaan berat tanpa cache.
Setelah menemukan query lambat, periksa sisi database:
where, orderBy, dan foreign key.CREATE INDEX idx_post_author_id ON posts(author_id);
CREATE INDEX idx_post_published_created ON posts(published, created_at DESC);Prisma memungkinkan mendefinisikan index langsung di schema.prisma dengan @@index, sehingga migrasi membawa index bersamanya.
Query yang deterministik (tanpa autentikasi, tanpa efek samping) bisa di-cache di CDN atau HTTP layer. Apollo Server mendukung cache hints yang menandai bagian response:
import { makeExecutableSchema } from "@graphql-tools/schema";
const schema = makeExecutableSchema({ typeDefs, resolvers });Kemudian di resolver, beri hint via info.cacheControl atau gunakan direktif @cacheControl:
type Post {
id: ID!
title: String! @cacheControl(maxAge: 300)
}
type Query {
posts: [Post!]! @cacheControl(maxAge: 60)
}Ini menghasilkan header Cache-Control pada response sehingga CDN dan browser bisa menyimpan hasil query. ETag menambah efisiensi: client mengirim If-None-Match dan server merespons 304 bila data belum berubah.
APQ membagi query menjadi dua langkah: request pertama mengirim query lengkap beserta hash-nya, server menyimpan pemetaan hash ke query. Request berikutnya hanya mengirim hash:
const server = new ApolloServer({
typeDefs,
resolvers,
persistedQueries: { ttl: 3600 },
});import { createHttpLink } from "@apollo/client/link/http";
const httpLink = createHttpLink({ uri: "/graphql", disableApq: false });Manfaatnya: payload request mengecil drastis (bandwidth hemat hingga puluhan persen), dan query tidak perlu di-parse berulang kali di server. Detail konfigurasi cache APQ di Redis akan dibahas di episode 20.
Untuk data yang sering dibaca dan jarang berubah, cache di level field dengan TTL:
const CACHE_TTL = 300;
async function getPost(id, ctx) {
const key = `post:${id}`;
const cached = await ctx.redis.get(key);
if (cached) return JSON.parse(cached);
const post = await ctx.db.posts.find(id);
await ctx.redis.set(key, JSON.stringify(post), "EX", CACHE_TTL);
return post;
}Cache invalidation adalah bagian tersulit. Strategi yang umum: hapus key saat data dimutasi (redis-cli DEL post:123), atau gunakan versi key (post:123:v2) yang di-bump saat skema data berubah. Untuk data yang sangat dinamis, sesuaikan TTL atau lewati cache sama sekali.
DataLoader (episode 9) sudah menangani batching per request. Optimasi lanjutannya:
const userLoader = new DataLoader(async (ids) => {
const cached = await ctx.redis.mget(ids.map((id) => `user:${id}`));
const missing = ids.filter((_, i) => cached[i] === null);
// ambil yang missing, simpan ke cache, lalu gabungkan
});Optimasi tanpa pengukuran hanyalah tebakan. Terapkan:
Apollo Studio memberi "field usage" yang menunjukkan field mana yang sebenarnya dipakai client — dasar untuk membersihkan schema yang tidak terpakai. Integrasi observability menyeluruh, termasuk OpenTelemetry dan Prometheus, dibahas di episode 24.
Inti yang harus dibawa pulang:
Di episode 20 selanjutnya kalian akan mempelajari caching architecture — caching server-side penuh dan parsial, lapisan cache dari CDN sampai Redis, normalized cache Apollo Client dengan type policies, cache updates dan eviction, hingga GraphQL CDN. Arsitektur caching end-to-end kalian akan lengkap!