CINXE.COM
GraphQL Best Practices | GraphQL
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="theme-color" content="#111" media="(prefers-color-scheme: dark)"/><meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/><style>:root{--nextra-primary-hue:319deg;--nextra-primary-saturation:100%;--nextra-navbar-height:4rem;--nextra-menu-height:3.75rem;--nextra-banner-height:2.5rem;--nextra-bg:250,250,250;}.dark{--nextra-primary-hue:319deg;--nextra-primary-saturation:100%;--nextra-bg:27,27,27;}</style><title>GraphQL Best Practices | GraphQL</title><meta property="og:title" content="GraphQL Best Practices | GraphQL"/><meta property="og:image" content="/img/og-image.png"/><meta property="twitter:site" content="@graphql"/><meta name="next-head-count" content="8"/><link rel="preload" href="/_next/static/media/83d7d13e2307bc53-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/92f44bb82993d879-s.p.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/css/7c5bc1db88b085f4.css" as="style"/><link rel="stylesheet" href="/_next/static/css/7c5bc1db88b085f4.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/_next/static/chunks/webpack-431ca528a6392c6a.js" defer=""></script><script src="/_next/static/chunks/framework-66a3842b975d4c52.js" defer=""></script><script src="/_next/static/chunks/main-673357edd7232b24.js" defer=""></script><script src="/_next/static/chunks/pages/_app-97f7c54e0ee7d59a.js" defer=""></script><script src="/_next/static/chunks/7487-91cae87c9f405cbe.js" defer=""></script><script src="/_next/static/chunks/4692-0821ed55f70c918b.js" defer=""></script><script src="/_next/static/chunks/pages/learn/best-practices-dc6bd980a42b6774.js" defer=""></script><script src="/_next/static/ANYoRcQUjMjxlujFCfpei/_buildManifest.js" defer=""></script><script src="/_next/static/ANYoRcQUjMjxlujFCfpei/_ssgManifest.js" defer=""></script><style id="__jsx-3927496071">html{font-family:'__Roboto_Flex_d05349', '__Roboto_Flex_Fallback_d05349'}.roboto-mono{font-family:'__Roboto_Mono_c9cbed', '__Roboto_Mono_Fallback_c9cbed'}</style></head><body><div id="__next"><script>!function(){try{var d=document.documentElement,c=d.classList;c.remove('light','dark');var e=localStorage.getItem('theme');if('system'===e||(!e&&true)){var t='(prefers-color-scheme: dark)',m=window.matchMedia(t);if(m.media!==t||m.matches){d.style.colorScheme = 'dark';c.add('dark')}else{d.style.colorScheme = 'light';c.add('light')}}else if(e){c.add(e|| '')}if(e==='light'||e==='dark')d.style.colorScheme=e}catch(e){}}()</script><div dir="ltr"><script>document.documentElement.setAttribute('dir','ltr')</script><script>try{if(localStorage.getItem("graphqlconf-2024")==='0'){document.body.classList.add('nextra-banner-hidden')}}catch(e){}</script><div class="nextra-banner-container max-md:_sticky _top-0 _z-20 _flex _items-center _h-[var(--nextra-banner-height)] [body.nextra-banner-hidden_&]:_hidden _text-slate-50 dark:_text-white _bg-neutral-900 dark:_bg-[linear-gradient(1deg,#383838,#212121)] _px-2 _ps-10 print:_hidden"><div class="_w-full _truncate _text-center _font-medium _text-sm">🎬 That's a Wrap for GraphQLConf 2024! • Watch the Videos •<!-- --> <a class="underline after:content-['_→'] after:font-sans" href="/conf/2024/">Check out the recorded talks and workshops</a></div><button type="button" aria-label="Dismiss banner" class="_w-8 _h-8 _opacity-80 hover:_opacity-100"><svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" class="_mx-auto _h-4 _w-4"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button></div><div class="nextra-nav-container _sticky _top-0 _z-20 _w-full _bg-transparent print:_hidden"><div class="nextra-nav-container-blur"></div><nav class="_mx-auto _flex _h-[var(--nextra-navbar-height)] _max-w-[90rem] _items-center _justify-end _gap-4 _pl-[max(env(safe-area-inset-left),1.5rem)] _pr-[max(env(safe-area-inset-right),1.5rem)]"><a class="_flex _items-center hover:_opacity-75 ltr:_mr-auto rtl:_ml-auto" href="/"><svg xmlns="http://www.w3.org/2000/svg" style="fill:color(display-p3 .8824 0 .5961)" viewBox="0 0 367 100" class="h-8 nextra-logo" title="GraphQL"><path fill-rule="evenodd" d="m50 6.468 37.7 21.766v43.532L50 93.532 12.3 71.766V28.234zM16.53 30.676v31.976l27.692-47.964zM50 13.14 18.078 68.43h63.844zm27.692 59.52H22.308L50 88.648zm5.778-10.008L55.778 14.688 83.47 30.676z" clip-rule="evenodd"></path><circle cx="14.41" cy="29.45" r="8.91"></circle><circle cx="14.41" cy="70.545" r="8.91"></circle><circle cx="50" cy="91.09" r="8.91"></circle><circle cx="85.585" cy="70.545" r="8.91"></circle><circle cx="85.585" cy="29.455" r="8.91"></circle><circle cx="50" cy="8.91" r="8.91"></circle><path d="M138.875 71.625q-7.812 0-12.125-4.5t-4.562-12.062q-.063-1.876-.063-5.938t.063-5.937q.25-7.563 4.562-12.063t12.125-4.5q5.313 0 8.938 2 3.624 2 5.375 4.75 1.812 2.688 1.937 4.813v.124q0 .501-.375.813-.375.313-.938.313h-1.374q-.562 0-.813-.25t-.5-1q-1.062-3.313-4.125-5.563-3-2.25-8.125-2.25-5.812 0-9.187 3.188-3.313 3.187-3.563 9.937-.062 1.875-.062 5.625t.062 5.625q.25 6.75 3.563 9.938 3.375 3.186 9.187 3.187 5.813 0 9.375-3.312 3.562-3.314 3.562-9.813v-3.187h-10.874q-.625 0-1-.376a1.58 1.58 0 0 1-.375-1.062v-.875q0-.625.375-1 .375-.437 1-.437h13.374q.688 0 1.063.374.375.376.375 1.063v5.5q0 4.999-2 8.813-2 3.811-5.812 5.937-3.813 2.125-9.063 2.125M165.941 71q-.625 0-1-.375t-.375-1V39.938q0-.625.375-1 .375-.438 1-.438h1q.625 0 1 .438.438.375.438 1v2.874q2.25-4.312 8.5-4.312h2.312q.625 0 1 .375t.375 1v.875q0 .625-.375 1t-1 .375h-2.687q-3.75 0-5.938 2.188-2.187 2.187-2.187 5.937v19.375q0 .625-.438 1-.375.375-1 .375zM194.557 71.625q-3 0-5.563-1.25T184.869 67q-1.5-2.126-1.5-4.687 0-4.125 3.313-6.75 3.374-2.625 9.062-3.376l9.875-1.374v-2.188q0-3.438-2.125-5.25-2.063-1.875-6.375-1.875-3.188 0-5.25 1.25-2 1.25-2.562 3-.25.75-.625 1.063-.313.25-.875.25h-.875q-.563 0-1-.376a1.5 1.5 0 0 1-.375-1q0-1.374 1.25-3.187 1.25-1.875 3.875-3.25t6.437-1.375q6.687 0 9.5 3.188 2.813 3.187 2.813 7.75v20.812q0 .625-.375 1-.376.375-1 .375h-1.063q-.625 0-1-.375t-.375-1v-2.937q-1.375 2.061-4.062 3.5-2.626 1.437-7 1.437m.625-3.625q4.561 0 7.5-3 2.937-3 2.937-8.625V54.25l-8.062 1.125q-5.125.687-7.75 2.375T187.182 62q0 2.875 2.375 4.438Q191.994 68 195.182 68M220.752 82.875q-.624 0-1-.375-.375-.375-.375-1V39.875q0-.625.375-1 .376-.375 1-.375h1.063q.625 0 1 .375t.375 1v2.938q3.626-4.938 10.5-4.938 6.75 0 9.937 4.313 3.25 4.25 3.438 10.5.063.624.062 2.062 0 1.437-.062 2.063-.187 6.25-3.438 10.562-3.187 4.25-9.937 4.25-6.813 0-10.5-4.937V81.5q0 .625-.375 1t-1 .375zM233.315 68q5.062 0 7.375-3.187 2.375-3.25 2.562-8.313.063-.625.063-1.75 0-5.813-2.25-9.5-2.25-3.75-7.75-3.75-4.938 0-7.438 3.313-2.5 3.25-2.687 7.687l-.063 2.438.063 2.437a12.8 12.8 0 0 0 1.187 5.125q1.125 2.375 3.375 3.938Q230.002 68 233.315 68M257.068 71q-.625 0-1-.375t-.375-1V28q0-.625.375-1t1-.375h1.063q.625 0 1 .375t.375 1v14.813q1.875-2.439 4.25-3.688 2.437-1.25 6.25-1.25 6.125 0 9.437 3.938 3.313 3.874 3.313 10.062v17.75q0 .625-.375 1t-1 .375h-1.063q-.625 0-1-.375t-.375-1V52.188q0-5.063-2.5-7.876-2.437-2.812-7.062-2.812-4.5 0-7.188 2.875-2.687 2.813-2.687 7.813v17.437q0 .625-.375 1t-1 .375zM321.682 75.063q-.938 0-2-1.438l-2.75-3.812q-3.75 1.812-8.75 1.812-16.062 0-16.5-17.25-.062-1.875-.062-5.25t.062-5.25q.25-8.5 4.625-12.875t11.875-4.375T320.057 31t4.625 12.875q.125 3.75.125 5.25t-.125 5.25q-.312 8.937-4.562 13.125l4 5.625q.187.376.187.688a1.2 1.2 0 0 1-.375.874 1.2 1.2 0 0 1-.875.376zm-13.5-7.188q5.625 0 8.938-3.375 3.375-3.437 3.625-10.437.125-3.75.125-4.938t-.125-4.937q-.25-7-3.625-10.376-3.375-3.437-8.938-3.437-5.562 0-8.937 3.438-3.375 3.375-3.625 10.374-.063 1.875-.063 4.938t.063 4.938q.25 6.999 3.562 10.437 3.375 3.375 9 3.375M336.126 71q-.625 0-1-.375t-.375-1v-41q0-.625.375-1t1-.375h1.188q.625 0 1 .375t.375 1V67.25h21.562q.688 0 1.063.375t.375 1.063v.937q0 .625-.438 1-.375.375-1 .375z"></path></svg></a><a class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 max-md:_hidden _whitespace-nowrap _font-medium _subpixel-antialiased" aria-current="true" href="/learn/">Learn</a><div class="_relative" data-headlessui-state=""><button class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 _text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200 max-md:_hidden _items-center _whitespace-nowrap _rounded _flex _gap-1" id="headlessui-menu-button-:Rkl56:" type="button" aria-haspopup="menu" aria-expanded="false" data-headlessui-state="">Community<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="_h-[18px] _min-w-[18px] _rounded-sm _p-0.5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="_origin-center _transition-transform _rotate-90"></path></svg></button></div><a class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 max-md:_hidden _whitespace-nowrap _text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200" aria-current="false" href="/faq/">FAQ</a><a href="https://spec.graphql.org" target="_blank" rel="noreferrer" class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 max-md:_hidden _whitespace-nowrap _text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200" aria-current="false"><span class="after:content-['_↗'] after:font-sans">Spec</span></a><a class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 max-md:_hidden _whitespace-nowrap _text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200" aria-current="false" href="/blog/">Blog</a><a class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 max-md:_hidden _whitespace-nowrap _text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200" aria-current="false" href="/conf/2024/">GraphQLConf</a><a class="_text-sm contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100 max-md:_hidden _whitespace-nowrap _text-gray-600 hover:_text-gray-800 dark:_text-gray-400 dark:hover:_text-gray-200" aria-current="false" href="/graphql-js/">GraphQL.JS Tutorial</a><div class="nextra-search _relative md:_w-64 max-md:_hidden"><div class="_relative _flex _items-center _text-gray-900 contrast-more:_text-gray-800 dark:_text-gray-300 contrast-more:dark:_text-gray-300"><input spellcheck="false" class="_w-full _appearance-none _rounded-lg _px-3 _py-2 _transition-colors _text-base _leading-tight md:_text-sm _bg-black/[.05] dark:_bg-gray-50/10 focus:!_bg-transparent placeholder:_text-gray-500 dark:placeholder:_text-gray-400 contrast-more:_border contrast-more:_border-current" type="search" placeholder="Search…" value=""/></div></div><button title="Change theme" class="_h-7 _rounded-md _px-2 _text-left _text-xs _font-medium _text-gray-600 _transition-colors dark:_text-gray-400 hover:_bg-gray-100 hover:_text-gray-900 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 [&_span]:hidden" id="headlessui-listbox-button-:R5l56:" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state=""><div class="_flex _items-center _gap-2 _capitalize"><svg fill="none" viewBox="3 3 18 18" width="12" height="12" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="currentColor" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg><span class="md:_hidden">Light</span></div></button><button type="button" aria-label="Menu" class="nextra-hamburger _rounded active:_bg-gray-400/20 md:_hidden"><svg fill="none" width="24" height="24" viewBox="0 0 24 24" stroke="currentColor" class=""><g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16"></path></g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16"></path><g><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 18h16"></path></g></svg></button></nav></div><div class="_mx-auto _flex _max-w-[90rem]"><div class="motion-reduce:_transition-none [transition:background-color_1.5s_ease] _bg-transparent"></div><aside class="nextra-sidebar-container _flex _flex-col md:_top-16 md:_shrink-0 motion-reduce:_transform-none _transform-gpu _transition-all _ease-in-out print:_hidden md:_w-64 md:_sticky md:_self-start max-md:[transform:translate3d(0,-100%,0)]"><div class="_px-4 _pt-4 md:_hidden"><div class="nextra-search _relative md:_w-64"><div class="_relative _flex _items-center _text-gray-900 contrast-more:_text-gray-800 dark:_text-gray-300 contrast-more:dark:_text-gray-300"><input spellcheck="false" class="_w-full _appearance-none _rounded-lg _px-3 _py-2 _transition-colors _text-base _leading-tight md:_text-sm _bg-black/[.05] dark:_bg-gray-50/10 focus:!_bg-transparent placeholder:_text-gray-500 dark:placeholder:_text-gray-400 contrast-more:_border contrast-more:_border-current" type="search" placeholder="Search…" value=""/></div></div></div><div class="_overflow-y-auto _overflow-x-hidden _p-4 _grow md:_h-[calc(100vh-var(--nextra-navbar-height)-var(--nextra-menu-height))] nextra-scrollbar"><div class="_transform-gpu _overflow-hidden _transition-all _ease-in-out motion-reduce:_transition-none"><div class="_transition-opacity _duration-500 _ease-in-out motion-reduce:_transition-none _opacity-100"><ul class="_flex _flex-col _gap-1 nextra-menu-desktop max-md:_hidden"><li class="[word-break:break-word] [&:not(:first-child)]:_mt-5 _mb-2 _px-2 _py-1.5 _text-sm _font-semibold _text-gray-900 dark:_text-gray-100">Learn</li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/">Introduction</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/schema/">Schemas and Types</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/queries/">Queries</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/mutations/">Mutations</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/subscriptions/">Subscriptions</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/validation/">Validation</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/execution/">Execution</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/response/">Response</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/introspection/">Introspection</a></li><li class="[word-break:break-word] [&:not(:first-child)]:_mt-5 _mb-2 _px-2 _py-1.5 _text-sm _font-semibold _text-gray-900 dark:_text-gray-100">Best Practices</li><li class="_flex _flex-col _gap-1 active"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _bg-primary-100 _font-semibold _text-primary-800 dark:_bg-primary-400/10 dark:_text-primary-600 contrast-more:_border-primary-500 contrast-more:dark:_border-primary-500" href="/learn/best-practices/">Best Practices</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/thinking-in-graphs/">Thinking in Graphs</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/serving-over-http/">Serving over HTTP</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/authorization/">Authorization</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/pagination/">Pagination</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/global-object-identification/">Global Object Identification</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/caching/">Caching</a></li><li class="_flex _flex-col _gap-1"><a class="_flex _rounded _px-2 _py-1.5 _text-sm _transition-colors [word-break:break-word] _cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:_border _text-gray-500 hover:_bg-gray-100 hover:_text-gray-900 dark:_text-neutral-400 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50 contrast-more:_text-gray-900 contrast-more:dark:_text-gray-50 contrast-more:_border-transparent contrast-more:hover:_border-gray-900 contrast-more:dark:hover:_border-gray-50" href="/learn/security/">Security</a></li></ul></div></div></div><div class="nextra-sidebar-footer _sticky _bottom-0 _flex _items-center _gap-2 _mx-4 _py-4" data-toggle-animation="off"><div class="_grow _flex _flex-col"><button title="Change theme" class="_h-7 _rounded-md _px-2 _text-left _text-xs _font-medium _text-gray-600 _transition-colors dark:_text-gray-400 hover:_bg-gray-100 hover:_text-gray-900 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50" id="headlessui-listbox-button-:R2njd6:" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state=""><div class="_flex _items-center _gap-2 _capitalize"><svg fill="none" viewBox="3 3 18 18" width="12" height="12" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="currentColor" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg><span class="">Light</span></div></button></div><button title="Hide sidebar" class="max-md:_hidden _h-7 _rounded-md _transition-colors _text-gray-600 dark:_text-gray-400 _px-2 hover:_bg-gray-100 hover:_text-gray-900 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50"><svg height="12" width="12" viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M4.177 7.823l2.396-2.396A.25.25 0 017 5.604v4.792a.25.25 0 01-.427.177L4.177 8.177a.25.25 0 010-.354z" class=""></path><path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm1.75-.25a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25H9.5v-13H1.75zm12.5 13H11v-13h3.25a.25.25 0 01.25.25v12.5a.25.25 0 01-.25.25z"></path></svg></button></div></aside><nav class="nextra-toc _order-last max-xl:_hidden _w-64 _shrink-0 print:_hidden _px-4" aria-label="table of contents"><div class="nextra-scrollbar _sticky _top-16 _overflow-y-auto _pr-4 _pt-6 _text-sm [hyphens:auto] _max-h-[calc(100vh-var(--nextra-navbar-height)-env(safe-area-inset-bottom))] ltr:_-mr-4 rtl:_-ml-4"><p class="_mb-4 _font-semibold _tracking-tight">On This Page</p><ul><li class="_my-2 _scroll-my-6 _scroll-py-6"><a href="#http" class="_font-semibold _inline-block _transition-colors _subpixel-antialiased _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-300 contrast-more:_text-gray-900 contrast-more:_underline contrast-more:dark:_text-gray-50 _w-full _break-words">HTTP</a></li><li class="_my-2 _scroll-my-6 _scroll-py-6"><a href="#json-with-gzip" class="_font-semibold _inline-block _transition-colors _subpixel-antialiased _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-300 contrast-more:_text-gray-900 contrast-more:_underline contrast-more:dark:_text-gray-50 _w-full _break-words">JSON (with GZIP)</a></li><li class="_my-2 _scroll-my-6 _scroll-py-6"><a href="#versioning" class="_font-semibold _inline-block _transition-colors _subpixel-antialiased _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-300 contrast-more:_text-gray-900 contrast-more:_underline contrast-more:dark:_text-gray-50 _w-full _break-words">Versioning</a></li><li class="_my-2 _scroll-my-6 _scroll-py-6"><a href="#nullability" class="_font-semibold _inline-block _transition-colors _subpixel-antialiased _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-300 contrast-more:_text-gray-900 contrast-more:_underline contrast-more:dark:_text-gray-50 _w-full _break-words">Nullability</a></li><li class="_my-2 _scroll-my-6 _scroll-py-6"><a href="#pagination" class="_font-semibold _inline-block _transition-colors _subpixel-antialiased _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-300 contrast-more:_text-gray-900 contrast-more:_underline contrast-more:dark:_text-gray-50 _w-full _break-words">Pagination</a></li><li class="_my-2 _scroll-my-6 _scroll-py-6"><a href="#server-side-batching--caching" class="_font-semibold _inline-block _transition-colors _subpixel-antialiased _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-300 contrast-more:_text-gray-900 contrast-more:_underline contrast-more:dark:_text-gray-50 _w-full _break-words">Server-side Batching & Caching</a></li></ul><div class="nextra-toc-footer _mt-8 _pt-8 _sticky _bottom-0 _flex _flex-col _items-start _gap-2 _pb-8"><a href="https://github.com/graphql/graphql.github.io/issues/new?title=Feedback%20for%20%E2%80%9CGraphQL%20Best%20Practices%E2%80%9D&labels=feedback" target="_blank" rel="noreferrer" class="_text-xs _font-medium _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-100 contrast-more:_text-gray-800 contrast-more:dark:_text-gray-50">Question? Give us feedback →</a><a class="_text-xs _font-medium _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-100 contrast-more:_text-gray-800 contrast-more:dark:_text-gray-50" href="https://github.com/graphql/graphql.github.io/tree/source/src/pages/learn/best-practices.mdx">Edit this page</a><button aria-hidden="true" disabled="" class="_flex _items-center _gap-1.5 _transition _opacity-100 disabled:_opacity-0 _text-xs _font-medium _text-gray-500 hover:_text-gray-900 dark:_text-gray-400 dark:hover:_text-gray-100 contrast-more:_text-gray-800 contrast-more:dark:_text-gray-50">Scroll to top<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="_-rotate-90 _size-4 _border _rounded-full _border-current"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg></button></div></div></nav><div id="reach-skip-nav"></div><article class="_w-full _break-words nextra-content _flex _min-h-[calc(100vh-var(--nextra-navbar-height))] _min-w-0 _justify-center _pb-8 _pr-[calc(env(safe-area-inset-right)-1.5rem)]"><main class="_w-full _min-w-0 _max-w-6xl _px-6 _pt-4 md:_px-12"><div class="nextra-breadcrumb _mt-1.5 _flex _items-center _gap-1 _overflow-hidden _text-sm _text-gray-500 dark:_text-gray-400 contrast-more:_text-current"><div class="_whitespace-nowrap _transition-colors _min-w-[24px] _overflow-hidden _text-ellipsis" title="Learn">Learn</div><svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="_w-3.5 _shrink-0"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg><div class="_whitespace-nowrap _transition-colors _font-medium _text-gray-700 contrast-more:_font-bold contrast-more:_text-current dark:_text-gray-100 contrast-more:dark:_text-current" title="Best Practices">Best Practices</div></div><h1 class="_mt-2 _text-4xl _font-bold _tracking-tight _text-slate-900 dark:_text-slate-100">GraphQL Best Practices</h1> <p class="[&:not(:first-child)]:_mt-6 _leading-7">The GraphQL specification is intentionally silent on a handful of important issues facing APIs such as dealing with the network, authorization, and pagination. This doesn’t mean that there aren’t solutions for these issues when using GraphQL, just that they’re outside the description about what GraphQL <em>is</em> and instead just common practice.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">The articles in this section should not be taken as gospel, and in some cases may rightfully be ignored in favor of some other approach. Some articles introduce some of the philosophy developed within Facebook around designing and deploying GraphQL services, while others are more tactical suggestions for solving common problems like serving over HTTP and performing authorization.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Following are brief descriptions of some of the more common best practices and opinionated stances held by GraphQL services, however each article in this section will go into more depth on these and other topics.</p> <h2 class="_font-semibold _tracking-tight _text-slate-900 dark:_text-slate-100 _mt-10 _border-b _pb-1 _text-3xl _border-neutral-200/70 contrast-more:_border-neutral-400 dark:_border-primary-100/10 contrast-more:dark:_border-neutral-400">HTTP<a href="#http" id="http" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="[&:not(:first-child)]:_mt-6 _leading-7">GraphQL is typically served over HTTP via a single endpoint which expresses the full set of capabilities of the service. This is in contrast to REST APIs which expose a suite of URLs each of which expose a single resource. While GraphQL could be used alongside a suite of resource URLs, this can make it harder to use with tools like <a href="https://github.com/graphql/graphiql" target="_blank" rel="noreferrer" class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]">GraphiQL</a>.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Read more about this in <a class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]" href="/learn/serving-over-http/">Serving over HTTP</a>.</p> <h2 class="_font-semibold _tracking-tight _text-slate-900 dark:_text-slate-100 _mt-10 _border-b _pb-1 _text-3xl _border-neutral-200/70 contrast-more:_border-neutral-400 dark:_border-primary-100/10 contrast-more:dark:_border-neutral-400">JSON (with GZIP)<a href="#json-with-gzip" id="json-with-gzip" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="[&:not(:first-child)]:_mt-6 _leading-7">GraphQL services typically respond using JSON, however the GraphQL spec <a href="http://spec.graphql.org/draft/#sec-Serialization-Format" target="_blank" rel="noreferrer" class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]">does not require it</a>. JSON may seem like an odd choice for an API layer promising better network performance, however because it is mostly text, it compresses exceptionally well with GZIP.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">It’s encouraged that any production GraphQL services enable GZIP and encourage their clients to send the header:</p> <div class="nextra-code _relative [&:not(:first-child)]:_mt-6"><pre class="_overflow-x-auto _subpixel-antialiased _text-[.9em] _bg-white dark:_bg-black _py-4 _ring-1 _ring-inset _ring-gray-300 dark:_ring-neutral-700 contrast-more:_ring-gray-900 contrast-more:dark:_ring-gray-50 contrast-more:_contrast-150 _rounded-md"><code class="nextra-code" dir="ltr">Accept-Encoding: gzip </code></pre><div class="_opacity-0 _transition [div:hover>&]:_opacity-100 focus-within:_opacity-100 _flex _gap-1 _absolute _right-4 _top-2"><button class="_transition _rounded-md _p-1.5 _border _border-gray-300 dark:_border-neutral-700 contrast-more:_border-gray-900 contrast-more:dark:_border-gray-50 md:_hidden" title="Toggle word wrap"><svg viewBox="0 0 24 24" width="24" height="24" class="_h-4 _w-auto"><path fill="currentColor" d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"></path></svg></button></div></div> <p class="[&:not(:first-child)]:_mt-6 _leading-7">JSON is also very familiar to client and API developers, and is easy to read and debug. In fact, the GraphQL syntax is partly inspired by the JSON syntax.</p> <h2 class="_font-semibold _tracking-tight _text-slate-900 dark:_text-slate-100 _mt-10 _border-b _pb-1 _text-3xl _border-neutral-200/70 contrast-more:_border-neutral-400 dark:_border-primary-100/10 contrast-more:dark:_border-neutral-400">Versioning<a href="#versioning" id="versioning" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="[&:not(:first-child)]:_mt-6 _leading-7">While there’s nothing that prevents a GraphQL service from being versioned just like any other REST API, GraphQL takes a strong opinion on avoiding versioning by providing the tools for the continuous evolution of a GraphQL schema.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Why do most APIs version? When there’s limited control over the data that’s returned from an API endpoint, <em>any change</em> can be considered a breaking change, and breaking changes require a new version. If adding new features to an API requires a new version, then a tradeoff emerges between releasing often and having many incremental versions versus the understandability and maintainability of the API.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">In contrast, GraphQL only returns the data that’s explicitly requested, so new capabilities can be added via new types and new fields on those types without creating a breaking change. This has led to a common practice of always avoiding breaking changes and serving a versionless API.</p> <h2 class="_font-semibold _tracking-tight _text-slate-900 dark:_text-slate-100 _mt-10 _border-b _pb-1 _text-3xl _border-neutral-200/70 contrast-more:_border-neutral-400 dark:_border-primary-100/10 contrast-more:dark:_border-neutral-400">Nullability<a href="#nullability" id="nullability" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Most type systems which recognise “null” provide both the common type and the <em>nullable</em> version of that type, whereby default types do not include “null” unless explicitly declared. However, in a GraphQL type system, every field is <em>nullable</em> by default. This is because there are many things that can go awry in a networked service backed by databases and other services. A database could go down, an asynchronous action could fail, an exception could be thrown. Beyond simply system failures, authorization can often be granular, where individual fields within a request can have different authorization rules.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">By defaulting every field to <em>nullable</em>, any of these reasons may result in just that field returned “null” rather than having a complete failure for the request. Instead, GraphQL provides <a class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]" href="/learn/schema/#lists-and-non-null">non-null</a> variants of types which make a guarantee to clients that if requested, the field will never return “null”. Instead, if an error occurs, the previous parent field will be “null” instead.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">When designing a GraphQL schema, it’s important to keep in mind all the problems that could go wrong and if “null” is an appropriate value for a failed field. Typically it is, but occasionally, it’s not. In those cases, use non-null types to make that guarantee.</p> <h2 class="_font-semibold _tracking-tight _text-slate-900 dark:_text-slate-100 _mt-10 _border-b _pb-1 _text-3xl _border-neutral-200/70 contrast-more:_border-neutral-400 dark:_border-primary-100/10 contrast-more:dark:_border-neutral-400">Pagination<a href="#pagination" id="pagination" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="[&:not(:first-child)]:_mt-6 _leading-7">The GraphQL type system allows for some fields to return <a class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]" href="/learn/schema/#lists-and-non-null">lists of values</a>, but leaves the pagination of longer lists of values up to the API designer. There are a wide range of possible API designs for pagination, each of which has pros and cons.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Typically, fields that could return long lists accept arguments “first” and “after” to allow for specifying a specific region of a list, where “after” is a unique identifier of each of the values in the list.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Ultimately designing APIs with feature-rich pagination led to a best practice pattern called “Connections”. Some client tools for GraphQL, such as <a href="https://facebook.github.io/relay/" target="_blank" rel="noreferrer" class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]">Relay</a>, know about the Connections pattern and can automatically provide support for client-side pagination when a GraphQL API employs this pattern.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">Read more about this in the article on <a class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]" href="/learn/pagination/">Pagination</a>.</p> <h2 class="_font-semibold _tracking-tight _text-slate-900 dark:_text-slate-100 _mt-10 _border-b _pb-1 _text-3xl _border-neutral-200/70 contrast-more:_border-neutral-400 dark:_border-primary-100/10 contrast-more:dark:_border-neutral-400">Server-side Batching & Caching<a href="#server-side-batching--caching" id="server-side-batching--caching" class="subheading-anchor" aria-label="Permalink for this section"></a></h2> <p class="[&:not(:first-child)]:_mt-6 _leading-7">GraphQL is designed in a way that allows you to write clean code on the server, where every field on every type has a focused single-purpose function for resolving that value. However without additional consideration, a naive GraphQL service could be very “chatty” or repeatedly load data from your databases.</p> <p class="[&:not(:first-child)]:_mt-6 _leading-7">This is commonly solved by a batching technique, where multiple requests for data from a backend are collected over a short period of time and then dispatched in a single request to an underlying database or microservice by using a tool like Facebook’s <a href="https://github.com/facebook/dataloader" target="_blank" rel="noreferrer" class="_text-primary-600 _underline _decoration-from-font [text-underline-position:from-font]">DataLoader</a>.</p><div class="_mt-16"></div><div class="_mb-8 _flex _items-center _border-t _pt-8 dark:_border-neutral-800 contrast-more:_border-neutral-400 dark:contrast-more:_border-neutral-400 print:_hidden"><a title="Introspection" class="_flex _max-w-[50%] _items-center _gap-1 _py-4 _text-base _font-medium _text-gray-600 _transition-colors [word-break:break-word] hover:_text-primary-600 dark:_text-gray-300 md:_text-lg ltr:_pr-4 rtl:_pl-4" href="/learn/introspection/"><svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="_inline _h-5 _shrink-0 ltr:_rotate-180"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>Introspection</a><a title="Thinking in Graphs" class="_flex _max-w-[50%] _items-center _gap-1 _py-4 _text-base _font-medium _text-gray-600 _transition-colors [word-break:break-word] hover:_text-primary-600 dark:_text-gray-300 md:_text-lg ltr:_ml-auto ltr:_pl-4 ltr:_text-right rtl:_mr-auto rtl:_pr-4 rtl:_text-left" href="/learn/thinking-in-graphs/">Thinking in Graphs<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="_inline _h-5 _shrink-0 rtl:_rotate-180"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg></a></div></main></article></div><footer class="_bg-gray-100 _pb-[env(safe-area-inset-bottom)] dark:_bg-neutral-900 print:_bg-transparent"><div class="_mx-auto _flex _max-w-[90rem] _gap-2 _py-2 _px-4 _hidden"><button title="Change theme" class="_h-7 _rounded-md _px-2 _text-left _text-xs _font-medium _text-gray-600 _transition-colors dark:_text-gray-400 hover:_bg-gray-100 hover:_text-gray-900 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50" id="headlessui-listbox-button-:R2jl6:" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state=""><div class="_flex _items-center _gap-2 _capitalize"><svg fill="none" viewBox="3 3 18 18" width="12" height="12" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="currentColor" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg><span class="">Light</span></div></button></div><hr class="dark:_border-neutral-800"/><div class="_mx-auto _flex _max-w-[90rem] _justify-center _py-12 _text-gray-600 dark:_text-gray-400 md:_justify-start _pl-[max(env(safe-area-inset-left),1.5rem)] _pr-[max(env(safe-area-inset-right),1.5rem)]"><div class="w-full"><div class="flex justify-between items-start mb-24 flex-wrap gap-10"><a class="max-lg:w-full" href="/"><svg xmlns="http://www.w3.org/2000/svg" style="fill:color(display-p3 .8824 0 .5961)" viewBox="0 0 367 100" class="h-8 nextra-logo" title="GraphQL"><path fill-rule="evenodd" d="m50 6.468 37.7 21.766v43.532L50 93.532 12.3 71.766V28.234zM16.53 30.676v31.976l27.692-47.964zM50 13.14 18.078 68.43h63.844zm27.692 59.52H22.308L50 88.648zm5.778-10.008L55.778 14.688 83.47 30.676z" clip-rule="evenodd"></path><circle cx="14.41" cy="29.45" r="8.91"></circle><circle cx="14.41" cy="70.545" r="8.91"></circle><circle cx="50" cy="91.09" r="8.91"></circle><circle cx="85.585" cy="70.545" r="8.91"></circle><circle cx="85.585" cy="29.455" r="8.91"></circle><circle cx="50" cy="8.91" r="8.91"></circle><path d="M138.875 71.625q-7.812 0-12.125-4.5t-4.562-12.062q-.063-1.876-.063-5.938t.063-5.937q.25-7.563 4.562-12.063t12.125-4.5q5.313 0 8.938 2 3.624 2 5.375 4.75 1.812 2.688 1.937 4.813v.124q0 .501-.375.813-.375.313-.938.313h-1.374q-.562 0-.813-.25t-.5-1q-1.062-3.313-4.125-5.563-3-2.25-8.125-2.25-5.812 0-9.187 3.188-3.313 3.187-3.563 9.937-.062 1.875-.062 5.625t.062 5.625q.25 6.75 3.563 9.938 3.375 3.186 9.187 3.187 5.813 0 9.375-3.312 3.562-3.314 3.562-9.813v-3.187h-10.874q-.625 0-1-.376a1.58 1.58 0 0 1-.375-1.062v-.875q0-.625.375-1 .375-.437 1-.437h13.374q.688 0 1.063.374.375.376.375 1.063v5.5q0 4.999-2 8.813-2 3.811-5.812 5.937-3.813 2.125-9.063 2.125M165.941 71q-.625 0-1-.375t-.375-1V39.938q0-.625.375-1 .375-.438 1-.438h1q.625 0 1 .438.438.375.438 1v2.874q2.25-4.312 8.5-4.312h2.312q.625 0 1 .375t.375 1v.875q0 .625-.375 1t-1 .375h-2.687q-3.75 0-5.938 2.188-2.187 2.187-2.187 5.937v19.375q0 .625-.438 1-.375.375-1 .375zM194.557 71.625q-3 0-5.563-1.25T184.869 67q-1.5-2.126-1.5-4.687 0-4.125 3.313-6.75 3.374-2.625 9.062-3.376l9.875-1.374v-2.188q0-3.438-2.125-5.25-2.063-1.875-6.375-1.875-3.188 0-5.25 1.25-2 1.25-2.562 3-.25.75-.625 1.063-.313.25-.875.25h-.875q-.563 0-1-.376a1.5 1.5 0 0 1-.375-1q0-1.374 1.25-3.187 1.25-1.875 3.875-3.25t6.437-1.375q6.687 0 9.5 3.188 2.813 3.187 2.813 7.75v20.812q0 .625-.375 1-.376.375-1 .375h-1.063q-.625 0-1-.375t-.375-1v-2.937q-1.375 2.061-4.062 3.5-2.626 1.437-7 1.437m.625-3.625q4.561 0 7.5-3 2.937-3 2.937-8.625V54.25l-8.062 1.125q-5.125.687-7.75 2.375T187.182 62q0 2.875 2.375 4.438Q191.994 68 195.182 68M220.752 82.875q-.624 0-1-.375-.375-.375-.375-1V39.875q0-.625.375-1 .376-.375 1-.375h1.063q.625 0 1 .375t.375 1v2.938q3.626-4.938 10.5-4.938 6.75 0 9.937 4.313 3.25 4.25 3.438 10.5.063.624.062 2.062 0 1.437-.062 2.063-.187 6.25-3.438 10.562-3.187 4.25-9.937 4.25-6.813 0-10.5-4.937V81.5q0 .625-.375 1t-1 .375zM233.315 68q5.062 0 7.375-3.187 2.375-3.25 2.562-8.313.063-.625.063-1.75 0-5.813-2.25-9.5-2.25-3.75-7.75-3.75-4.938 0-7.438 3.313-2.5 3.25-2.687 7.687l-.063 2.438.063 2.437a12.8 12.8 0 0 0 1.187 5.125q1.125 2.375 3.375 3.938Q230.002 68 233.315 68M257.068 71q-.625 0-1-.375t-.375-1V28q0-.625.375-1t1-.375h1.063q.625 0 1 .375t.375 1v14.813q1.875-2.439 4.25-3.688 2.437-1.25 6.25-1.25 6.125 0 9.437 3.938 3.313 3.874 3.313 10.062v17.75q0 .625-.375 1t-1 .375h-1.063q-.625 0-1-.375t-.375-1V52.188q0-5.063-2.5-7.876-2.437-2.812-7.062-2.812-4.5 0-7.188 2.875-2.687 2.813-2.687 7.813v17.437q0 .625-.375 1t-1 .375zM321.682 75.063q-.938 0-2-1.438l-2.75-3.812q-3.75 1.812-8.75 1.812-16.062 0-16.5-17.25-.062-1.875-.062-5.25t.062-5.25q.25-8.5 4.625-12.875t11.875-4.375T320.057 31t4.625 12.875q.125 3.75.125 5.25t-.125 5.25q-.312 8.937-4.562 13.125l4 5.625q.187.376.187.688a1.2 1.2 0 0 1-.375.874 1.2 1.2 0 0 1-.875.376zm-13.5-7.188q5.625 0 8.938-3.375 3.375-3.437 3.625-10.437.125-3.75.125-4.938t-.125-4.937q-.25-7-3.625-10.376-3.375-3.437-8.938-3.437-5.562 0-8.937 3.438-3.375 3.375-3.625 10.374-.063 1.875-.063 4.938t.063 4.938q.25 6.999 3.562 10.437 3.375 3.375 9 3.375M336.126 71q-.625 0-1-.375t-.375-1v-41q0-.625.375-1t1-.375h1.188q.625 0 1 .375t.375 1V67.25h21.562q.688 0 1.063.375t.375 1.063v.937q0 .625-.438 1-.375.375-1 .375z"></path></svg></a><ul class="text-sm flex flex-col gap-4 max-lg:w-[46%]"><h3 class="text-lg font-bold">Learn</h3><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/learn/">Introduction to GraphQL</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/learn/best-practices/">Best Practices</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/faq/">Frequently Asked Questions</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/community/resources/training-courses/">Training Courses</a></li></ul><ul class="text-sm flex flex-col gap-4 max-lg:w-[46%]"><h3 class="text-lg font-bold">Code</h3><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="https://github.com/graphql">GitHub</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="https://spec.graphql.org">GraphQL Specification</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/code/">Libraries & Tools</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/code/?tags=services">Services & Vendors</a></li></ul><ul class="text-sm flex flex-col gap-4 max-lg:w-[46%]"><h3 class="text-lg font-bold">Community</h3><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/community/resources/official-channels/">Resources</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/community/events/">Events & Meetups</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/community/contribute/essential-links/">Contribute to GraphQL</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="https://landscape.graphql.org">Landscape</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="https://store.graphql.org">Shop</a></li></ul><ul class="text-sm flex flex-col gap-4 max-lg:w-[46%]"><h3 class="text-lg font-bold">& More</h3><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/blog/">Blog</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/foundation/">GraphQL Foundation</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/foundation/community-grant/">GraphQL Community Grant</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/brand/">Logo and Brand Guidelines</a></li><li><a class="hover:underline decoration-from-font [text-underline-position:from-font]" href="/codeofconduct/">Code of Conduct</a></li></ul></div><div class="flex justify-between flex-wrap gap-10"><p class="text-sm">Copyright © <!-- -->2024<!-- --> The GraphQL Foundation. All rights reserved.<br/>For web site terms of use, trademark policy and general project policies please see<!-- --> <a href="https://lfprojects.org" target="_blank" rel="noreferrer" class="text-primary hover:underline decoration-from-font [text-underline-position:from-font]">https://lfprojects.org</a></p><div class="flex flex-col gap-4 lg:items-end"><ul class="flex gap-5"><li><a href="https://github.com/graphql" target="_blank" rel="noreferrer" class="hover:text-primary transition-colors block"><svg xmlns="http://www.w3.org/2000/svg" width="30" fill="currentColor" viewBox="0 0 30 30" class="h-5 w-auto *:fill-current"><path fill-rule="evenodd" d="M15.1.413a14.81 14.81 0 0 0-4.684 28.862c.742.138 1.012-.32 1.012-.712 0-.35-.013-1.283-.02-2.518-4.12.893-4.99-1.987-4.99-1.987-.675-1.71-1.643-2.165-1.643-2.165-1.345-.918.1-.9.1-.9 1.488.105 2.27 1.525 2.27 1.525 1.32 2.265 3.466 1.61 4.31 1.23.133-.955.515-1.608.94-1.978-3.29-.375-6.747-1.645-6.747-7.32 0-1.615.577-2.937 1.525-3.975-.15-.372-.66-1.88.145-3.917 0 0 1.242-.4 4.075 1.517a14.3 14.3 0 0 1 3.705-.5 14.2 14.2 0 0 1 3.707.5c2.826-1.915 4.068-1.517 4.068-1.517.807 2.037.3 3.545.15 3.92.95 1.035 1.52 2.357 1.52 3.975 0 5.687-3.462 6.94-6.76 7.305.53.457 1.005 1.36 1.005 2.742 0 1.98-.02 3.575-.02 4.063 0 .395.267.857 1.02.712A14.816 14.816 0 0 0 15.101.413" clip-rule="evenodd"></path></svg></a></li><li><a href="https://discord.graphql.org" target="_blank" rel="noreferrer" class="hover:text-primary transition-colors block"><svg xmlns="http://www.w3.org/2000/svg" fill="#5865f2" viewBox="0 0 20 20" class="h-5 w-auto *:fill-current"><path d="M16.956 3.693a16.5 16.5 0 0 0-4.134-1.274 10 10 0 0 0-.526 1.072 15.8 15.8 0 0 0-4.58 0 13 13 0 0 0-.525-1.072c-1.429.239-2.82.667-4.135 1.274C.44 7.553-.269 11.323.085 15.043a16.8 16.8 0 0 0 5.065 2.536q.614-.828 1.08-1.747a10.6 10.6 0 0 1-1.708-.82 6 6 0 0 0 .415-.323c3.295 1.507 6.864 1.507 10.119 0 .141.111.272.223.414.324-.546.323-1.112.596-1.709.818a12.3 12.3 0 0 0 1.083 1.75 16.8 16.8 0 0 0 5.064-2.538c.434-4.305-.689-8.045-2.952-11.35m-10.27 9.056c-.99 0-1.8-.9-1.8-2.002s.79-2.001 1.8-2.001c1 0 1.82.9 1.798 2.002 0 1.101-.798 2-1.798 2m6.641 0c-.99 0-1.8-.9-1.8-2.002s.79-2.001 1.8-2.001c1 0 1.82.9 1.8 2.002 0 1.101-.79 2-1.8 2"></path></svg></a></li><li><a href="https://twitter.com/graphql" target="_blank" rel="noreferrer" class="hover:text-primary transition-colors block"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20" class="h-5 w-auto *:fill-current"><path d="m11.396 9.473 5.461-6.216h-1.293L10.82 8.654 7.034 3.257H2.666l5.726 8.161-5.726 6.518H3.96l5.006-5.7 4 5.7h4.367M4.427 4.212h1.987l9.149 12.816h-1.988"></path></svg></a></li><li><a href="http://stackoverflow.com/questions/tagged/graphql" target="_blank" rel="noreferrer" class="hover:text-primary transition-colors block"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 124" class="h-5 w-auto *:fill-current"><path fill="#bbb" fill-rule="evenodd" d="M88 80h11v44H0V80h11v33h77z" clip-rule="evenodd"></path><path fill="#f58025" d="m22.988 76.73 54.025 11.355 2.27-10.8-54.024-11.36zm7.149-25.869 50.046 23.308 4.662-10.009-50.047-23.308zm13.848-24.553 42.428 35.331 7.066-8.485-42.428-35.33zM71.372.192l-8.86 6.59 32.948 44.3 8.86-6.589zM22 102h55V91H22z"></path></svg></a></li></ul><a href="https://nextra.site" target="_blank" rel="noreferrer" class="text-xs hover:text-primary transition-colors flex items-center gap-2">Powered by<!-- --> <svg viewBox="0 0 361 70" fill="currentColor" class="shrink-0 h-3"><path d="M114.913 33.2763v28.7642h-11.57V12.9496h11.059v8.3416h.575c1.129-2.7485 2.93-4.9325 5.401-6.5518 2.493-1.6193 5.572-2.429 9.237-2.429 3.388 0 6.339.7244 8.853 2.1733 2.535 1.4489 4.496 3.5476 5.88 6.2962 1.407 2.7486 2.099 6.0831 2.078 10.0035v31.2571h-11.57V32.5732c0-3.2813-.852-5.8487-2.557-7.7024-1.683-1.8537-4.016-2.7806-6.999-2.7806-2.024 0-3.824.4475-5.401 1.3424-1.556.8736-2.781 2.1413-3.676 3.8032-.873 1.662-1.31 3.6755-1.31 6.0405Zm61.407 29.723c-4.922 0-9.172-1.0227-12.752-3.0681-3.558-2.0668-6.296-4.9858-8.214-8.7572-1.917-3.7926-2.876-8.2563-2.876-13.3913 0-5.0497.959-9.4815 2.876-13.2954 1.939-3.8353 4.645-6.8182 8.118-8.9489 3.473-2.152 7.553-3.228 12.241-3.228 3.026 0 5.881.4901 8.565 1.4702 2.706.9588 5.093 2.4503 7.159 4.4744 2.088 2.0242 3.729 4.6023 4.922 7.7344 1.193 3.1108 1.79 6.8182 1.79 11.1221v3.5476h-40.238v-7.7983h29.148c-.021-2.2159-.501-4.1868-1.438-5.9126-.938-1.7472-2.248-3.1215-3.931-4.1229-1.662-1.0014-3.601-1.5021-5.817-1.5021-2.365 0-4.443.5753-6.232 1.7258-1.79 1.1293-3.186 2.6208-4.187 4.4745-.98 1.8324-1.481 3.8459-1.502 6.0405v6.8075c0 2.8551.522 5.3054 1.566 7.3508 1.044 2.0242 2.503 3.5796 4.378 4.6662 1.875 1.0654 4.07 1.598 6.584 1.598 1.683 0 3.207-.2343 4.57-.7031 1.364-.49 2.546-1.2038 3.548-2.1413 1.001-.9375 1.758-2.0987 2.269-3.4837l10.803 1.2145c-.682 2.8551-1.982 5.348-3.9 7.4787-1.896 2.1094-4.325 3.75-7.286 4.9219-2.962 1.1506-6.35 1.7258-10.164 1.7258Zm34.777-50.0497 9.908 18.1215 10.067-18.1215h12.241l-14.798 24.5455 15.054 24.5454h-12.177l-10.387-17.674-10.291 17.674h-12.273l14.957-24.5454-14.574-24.5455h12.273Zm63.878 0v8.9489h-28.221v-8.9489h28.221ZM253.722 1.18825h11.569V47.2749c0 1.5554.235 2.7486.704 3.5795.49.8097 1.129 1.3637 1.917 1.662s1.662.4474 2.621.4474c.724 0 1.385-.0532 1.981-.1598.618-.1065 1.087-.2024 1.407-.2876l1.949 9.0447c-.618.2131-1.502.4475-2.652.7031-1.13.2557-2.515.4049-4.155.4475-2.898.0852-5.508-.3516-7.831-1.3104-2.322-.9801-4.165-2.4929-5.529-4.5383-1.342-2.0455-2.003-4.6023-1.981-7.6705V1.18825Zm29.129 60.85225V12.9496h11.218v8.1818h.512c.895-2.8338 2.429-5.0177 4.602-6.5518 2.173-1.5554 4.677-2.3331 7.511-2.3331 1.321 0 2.535.1598 3.643.4794 1.108.3196 2.088.7564 2.94 1.3104l-3.579 9.588c-.618-.2983-1.3-.5433-2.046-.7351-.745-.1917-1.587-.2876-2.524-.2876-2.003 0-3.814.4474-5.434 1.3423-1.619.8949-2.908 2.1414-3.867 3.7394-.937 1.5767-1.406 3.4091-1.406 5.4971v28.8601h-11.57Zm51.222.863c-3.856 0-7.308-.9908-10.355-2.9723-3.047-1.9816-5.454-4.858-7.223-8.6293-1.768-3.7713-2.652-8.3523-2.652-13.7429 0-5.4546.894-10.0568 2.684-13.8068 1.811-3.7713 4.251-6.6158 7.319-8.5334 3.068-1.9389 6.488-2.9084 10.259-2.9084 2.877 0 5.242.4901 7.095 1.4702 1.854.9588 3.324 2.12 4.411 3.4836 1.087 1.3424 1.928 2.6101 2.525 3.8033h.479v-8.1179h11.602v49.0909h-11.378v-7.7343h-.703c-.597 1.1931-1.46 2.4609-2.589 3.8032-1.129 1.321-2.621 2.4503-4.474 3.3878-1.854.9375-4.187 1.4063-7 1.4063Zm3.228-9.4922c2.451 0 4.539-.6605 6.265-1.9816 1.725-1.3423 3.036-3.2066 3.931-5.593s1.342-5.1669 1.342-8.3416c0-3.1747-.447-5.934-1.342-8.2777-.874-2.3438-2.174-4.1655-3.9-5.4652-1.704-1.2997-3.803-1.9496-6.296-1.9496-2.578 0-4.73.6712-6.456 2.0135s-3.025 3.196-3.899 5.5611c-.873 2.365-1.31 5.071-1.31 8.1179 0 3.0682.437 5.8061 1.31 8.2138.895 2.3863 2.205 4.272 3.931 5.6569 1.747 1.3636 3.889 2.0455 6.424 2.0455Z"></path><path d="m64.8833 1.81335-2.8464 2.84638C47.1274 19.5692 22.9543 19.5692 8.04485 4.65972L5.19848 1.81335c-.93479-.93478-2.45037-.93478-3.38515 0-.93479.93478-.93478 2.45037 0 3.38515L4.6597 8.04487c14.9095 14.90953 14.9095 39.08263 0 53.99213l-2.84637 2.8463c-.93479.9348-.93479 2.4504 0 3.3852.93478.9348 2.45037.9348 3.38515 0l2.84637-2.8464c14.90955-14.9095 39.08255-14.9095 53.99205 0l2.8464 2.8464c.9348.9348 2.4504.9348 3.3852 0 .9347-.9348.9347-2.4504 0-3.3852l-2.8464-2.8463c-14.9095-14.9095-14.9095-39.0826 0-53.99213l2.8464-2.84637c.9347-.93478.9347-2.45037 0-3.38515-.9348-.93478-2.4504-.93478-3.3852 0Z" stroke="currentColor" stroke-width="2"></path></svg></a></div></div></div></div></footer></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/learn/best-practices","query":{},"buildId":"ANYoRcQUjMjxlujFCfpei","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>