Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Revisiting GraphQL in the RSC Era, and Co- Loca...

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

Revisiting GraphQL in the RSC Era, and Co- Located GraphQL Backend Inside Next.js

Avatar for Kenta Kudo

Kenta Kudo

January 27, 2026

More Decks by Kenta Kudo

Other Decks in Programming

Transcript

  1. #LT #GraphQL #Next.js #RouteHandlers #RSC Revisiting GraphQL in the RSC

    Era, and Co- Located GraphQL Backend Inside Next.js Kenta Kudo - Freelance Software Engineer React Osaka - Jan 2026 1
  2. About Me Freelance software engineer Previously at Mercari UK Lived

    in the UK for 6 years; returned to Japan 3 years ago Moved to Kansai last year — still very new to the area! 2
  3. Book Announcement 世界で働くエンジニア 10 Japanese software engineers working abroad Beta

    release now, official release at the end of this month Available as epub and pdf files (free updates) Spin-off from the London Tech Talk podcast community 3
  4. Today's Agenda 1. Introduction: Do we still need GraphQL? 2.

    Rediscover GraphQL: Straightforward queries and granular mutations 3. Co-Located Backend Architecture with Route Handlers 4. Recap: GraphQL can still be an option 5
  5. 1. Introduction — "Do we still need GraphQL?" The React

    Server Component Era RSC enables server-side data fetching per component Prior to RSC... Next.js pages router data fetching was page-level fetch all data in a single query Recent argument: "GraphQL is less necessary for RSC" My Realization GraphQL benefits go beyond fetching all data at once Still useful for contract + ergonomics 6
  6. 2. Rediscover GraphQL — Straightforward Queries Graph Structure query GetUserWithPosts($id:

    ID!) { user(id: $id) { name posts { title content } } } Query resources as a graph and traverse relations Discoverability via schema/introspection (when enabled) + dev tooling like GraphiQL 7
  7. 2. Rediscover GraphQL — Ergonomic Mutations REST API PATCH /posts/:id

    PATCH often leads to broad input shapes Resource-oriented endpoints carry big responsibility APIs often consolidate updates into broader endpoints More business logic on the client 8
  8. 2. Rediscover GraphQL — Ergonomic Mutations GraphQL mutation UpdatePostTitle($id: ID!,

    $title: String!) { updatePostTitle(id: $id, title: $title) { post { id title } } } Advantages: RPC-style mutations make intent explicit Business logic surfaces at the interface level First-class typed arguments, discoverability, consistent ergonomics 9
  9. 3. Co-Located Backend Architecture — with Route Handlers Next.js Route

    Handlers Server-side execution accessed like a backend API App Router → Route Handlers Pages Router → API Routes Growing Trend Building Next.js apps without a separate backend service using Route Handlers 10
  10. 3. Co-Located Backend Architecture — with Route Handlers Template Available

    GitHub repository template: GraphQL + Route Handlers https://github.com/KentaKudo/next-graphql-handler Note: This template demonstrates the core concepts and is not intended for production; add auth, error handling, etc. 11
  11. 3. Co-Located Backend Architecture — Route Handlers /api/graphql/route.ts import {

    createYoga } from "graphql-yoga"; import { schema } from "./schema"; const { handleRequest } = createYoga({ graphqlEndpoint: "/api/graphql", fetchAPI: { Response }, schema, }); export { handleRequest as GET, handleRequest as POST }; For Apollo Server → @as-integrations/next 12
  12. 3. Co-Located Backend Architecture — Client Side Tech Stack graphql-codegen:

    Generate TypeScript from GraphQL queries urql: GraphQL client library Hit /api/graphql endpoint 13
  13. 3. Co-Located Backend Architecture — Client Side urql Client Setup

    (Server Components) // lib/urql.ts import { cacheExchange, createClient, fetchExchange } from "@urql/core"; import { registerUrql } from "@urql/next/rsc"; const makeClient = () => createClient({ url: "http://localhost:3000/api/graphql", exchanges: [cacheExchange, fetchExchange], }); export const { getClient } = registerUrql(makeClient); 14
  14. 3. Co-Located Backend Architecture — Client Side Example: Server Component

    import { graphql } from "@/graphql"; import { getClient } from "@/lib/urql"; const helloQuery = graphql(` query Hello { hello(name: "from server component") } `); export default async function Home() { const result = await getClient().query(helloQuery, {}).toPromise(); if (result.error) { return <div>Error: {result.error.message}</div>; } return <div>Hello: {result.data?.hello}</div>; } 15
  15. 3. Co-Located Backend Architecture — Client Side urql Client Setup

    (Client Components) // app/providers/urql.tsx "use client"; import type { ReactNode } from "react"; import { createClient, UrqlProvider as NextUrqlProvider } from "@urql/next"; import { cacheExchange, fetchExchange } from "@urql/core"; const client = createClient({ url: "/api/graphql", exchanges: [cacheExchange, fetchExchange], }); export const UrqlProvider = ({ children }: { children: ReactNode }) => ( <NextUrqlProvider value={client}>{children}</NextUrqlProvider> ); 16
  16. 3. Co-Located Backend Architecture — Client Side Example: Client Component

    "use client"; import { graphql } from "@/graphql"; import { useQuery } from "@urql/next"; const helloQuery = graphql(` query HelloFromClientComponent { hello(name: "from client component") } `); export const ClientComponent = () => { const [result] = useQuery({ query: helloQuery }); if (result.error) { return <div>Error: {result.error.message}</div>; } return <div>ClientComponent: {result.data?.hello}</div>; }; 17
  17. 4. Recap — When GraphQL Still Shines RSC + BFF

    Pattern RSC enables co-located fetching, but you can still benefit from: Typed, discoverable, stable contract (GraphQL schema) Powerful combination: Flexible graph queries & ergonomic mutations (RPC- style) Co-Located Architecture: Next.js + GraphQL + Route Handlers Bottom Line RSC changes where you fetch, not what your interface contract should be 18
  18. References Recommended Reading: Black Hat GraphQL https://nostarch.com/black-hat-graphql DoS via expensive

    queries (deeply nested queries) Authorization pitfalls (forgetting field-level checks) Information disclosure (introspection in production) Template Repository https://github.com/KentaKudo/next-graphql-handler 世界で働くエンジニア Book: https://store.london-tech- talk.com/products/book_engineers_working_abroad London Tech Talk Podcast: https://london-tech-talk.com/ 19
  19. APPX. Easy Migration Want to spin up a separate server?

    → Yoga is framework-agnostic; only the adapter changes → Just hook the Yoga instance into Express, Hono, etc. → Keep React/Next.js-specific code in the binding layer 21
  20. APPX. Code-first vs Schema-first Code-first Generate GraphQL schema from codebase

    → Code is the source of truth When to choose: Great DX in TypeScript mono-repo Schema-first Write schema, generate resolver skeleton → Schema is the source of truth When to choose: Language-agnostic teams / schema governance My Preference: Code-first with Pothos Template uses Pothos GraphQL for code-first approach 22
  21. APPX. Code-first Example with Pothos import SchemaBuilder from "@pothos/core"; const

    builder = new SchemaBuilder({}); builder.queryType({ fields: (t) => ({ hello: t.string({ args: { name: t.arg.string() }, resolve: (parent, { name }) => `hello, ${name || "World"}`, }), }), }); export const schema = builder.toSchema(); Type-safe, concise, and TypeScript-native 23
  22. APPX. Production Considerations — GraphQL is Powerful: Protect It Security

    & Performance Authorization: Field-level auth (not only route level) N+1 Prevention: Batching / DataLoader patterns Query Complexity: Depth & cost limits Introspection: Disable in production (or gate it) Error Masking: Don't leak internal errors Rate Limiting: Protect against abuse 24