Relay: the GraphQL client that wants to do the dirty work for you
Tags: react, graphql, relay
Published: 2020-04-16 20:44:10

> This series of articles is written by [Gabriel Nordeborn](https://github.com/zth) and [Sean Grove](https://github.com/sgrove). Gabriel is a frontend developer and partner at the Swedish IT consultancy [Arizon](https://arizon.se) and has been using Relay for a long time. Sean is a co-founder of [OneGraph.com](https://www.onegraph.com), unifying 3rd-party APIs with GraphQL.

This is a series of articles that will dive juuuuust deep enough into Relay to answer - *definitively* - one question:


Why in the world would I care about Relay, Facebook’s JavaScript client framework for building applications using GraphQL?

It’s a good question, no doubt. In order to answer it, we’ll take you through parts of building a simple page rendering a blog. When building the page, we’ll see two main themes emerge:


1. Relay is, in fact, an utter workhorse that *wants* to do the dirty work for you.
2. If you follow the conventions Relay lays out, Relay will give you back a fantastic developer experience for building client side applications using GraphQL.

We’ll also show you that Relay applications are scalable, performant, modular, and resilient to change *by default,* and apps built with it are future proofed for the new features in development for React right now.

Relay comes with a (relatively minor) set of costs, which we’ll examine honestly and up-front, so the tradeoffs are well understood.

## Setting the stage

This article is intended to showcase the ideas and philosophy of *Relay*. While we occasionally contrast how Relay does things against other GraphQL frameworks, this article is not primarily intended as a comparison of Relay and other frameworks. We want to talk about and dive deep into *Relay* all by itself, explain its philosophy and the concepts involved in building applications with it. 

This also means that the code samples in this article (there are a few!) are only here to illustrate how Relay works, meaning they can be a bit shallow and simplified at times.

We’ll also focus exclusively on the new [hooks-based APIs for Relay](https://relay.dev/docs/en/experimental/step-by-step), which come fully-ready for React’s Suspense and Concurrent Mode. While the new APIs are still marked as experimental, Facebook is rebuilding facebook.com using Relay and said APIs exclusively for the data layer.

Also, before we start - this article will assume basic familiarity with GraphQL and building client side JavaScript applications. [Here’s an excellent introduction to GraphQL](https://graphql.org/learn/) if you feel you’re not quite up to speed. Code samples will be in TypeScript, so a basic understanding of that will help too.

*Finally*, this article is pretty long. See this as a reference article you can come back to over time.


With all the disclaimers out of the way, let’s get going!

# Quick overview of Relay
> Relay is made up of a compiler that optimizes your GraphQL code, and a library you use with React.

Before we dive into the deep end of the pool, let’s start with a quick overview of Relay. Relay can be divided into two parts:

1. The *compiler*: responsible for all sorts of optimizations, type generation, and enabling the great developer experience. You keep it running in the background as you develop.
2. The *library*: the core of Relay, and bindings to use Relay with React.

At this point, all you need to know about the compiler is that it’s a separate process you start that watches and compiles all of your GraphQL operations. You'll hear more about it soon though.

In addition to this, for Relay to work optimally, it wants your schema to follow three conventions:

- All `id` fields on types should be *globally unique* (i.e. no two objects - even two different *kinds* of objects - may share the same `id` value)*.*
- The `Node` interface, meaning: objects in the graph should be fetchable via their `id` field using a top level `node` field. Read more about globally unique id’s and the `Node` interface (and why it’s nice!) [here](https://dev.to/zth/the-magic-of-the-node-interface-4le1).
- Pagination should follow the connection based pagination standard. Read more about what connection based pagination is and why it is a good idea [in this article](https://dev.to/zth/connection-based-pagination-in-graphql-2588).

We won’t dive into the conventions any deeper at this point, but you’re encouraged to check out the articles linked above if you’re interested.

# At the heart of Relay: the fragment

Let’s first talk about a concept that's at the core of how Relay integrates with GraphQL: Fragments. It’s one of the main keys to Relay (and GraphQL!)'s powers, after all.

Simply put, fragments in GraphQL are a way to group together common selections on a specific GraphQL type. Here’s an example:

```graphql
    fragment Avatar_user on User {
      avatarUrl
      firstName
      lastName
    }
```

> For the curious: Naming the fragment `Avatar_user` is a convention that Relay enforces. Relay wants all fragment names to be globally unique, and to follow the structure of `<moduleName>_<propertyName>`. You can read more about naming conventions for fragments [here](https://relay.dev/docs/en/experimental/a-guided-tour-of-relay#fragments), and we'll talk about _why_ this is useful soon.

This defines a fragment called `Avatar_user` that can be used with the GraphQL type `User`. The fragment selects what’s typically needed to render an avatar. You can then re-use that fragment throughout your queries instead of explicitly selecting all fields needed for rendering the avatar at each place where you need them:

```graphql
    # Instead of doing this when you want to render the avatar for the author 
    # and the first two who liked the blog post...
    query BlogPostQuery($blogPostId: ID!) {
      blogPostById(id: $blogPostId) {
        author {
          firstName
          lastName
          avatarUrl
        }
        likedBy(first: 2) {
          edges {
            node {
              firstName
              lastName
              avatarUrl
            }
          }
        }
      }
    }
    
    # ...you can do this
    query BlogPostQuery($blogPostId: ID!) {
      blogPostById(id: $blogPostId) {
        author {
          ...Avatar_user
        }
        likedBy(first: 2) {
          edges {
            node {
              ...Avatar_user
            }
          }
        }
      }
    }
```

This is convenient because it allows reusing the definition, but more importantly it lets you add and remove fields that are needed to render your avatar as your application evolves *in a single place*. 


> Fragments allow you to define reusable selections of fields on GraphQL types.

## Relay doubles down on fragments

To scale a GraphQL client application over time, it’s a good practice to try and co-locate your data requirements with the components that render said data. This will make maintenance and extending your components much easier, as reasoning about your component and what data it uses is done in a single place. 

Since GraphQL fragments allow you to define sub-selections of fields on specific GraphQL types (as outlined above), they fit the co-location idea perfectly. 

So, a great practice is to define one or more fragments describing the data your component needs to render. This means that a component can say, “I depend on these 3 field from the `User` type, regardless of who my parent component is.” In the example above, there would be a component called `<Avatar />` that would show an avatar using the fields defined in the `Avatar_user` fragment.

Now, most frameworks let you use GraphQL fragments one way or another. But Relay takes this further. In Relay, almost *everything revolves around fragments*.

# How Relay supercharges the GraphQL fragment
At its core, Relay wants every component to have a complete, explicit list of all of its data requirements listed alongside the component itself. This allows Relay to integrate deeply with fragments. Let’s break down what this means, and what it enables.

## Co-located data requirements and modularity

With Relay, you use fragments to put the component’s data requirements right next to the code that’s actually using it. Following Relay's conventions guarantees that every component explicitly lists every field it needs access to. This means that no component will depend on data it doesn't explicitly ask for, making components modular, self-contained and resilient in the face of reuse and refactoring.

Relay does a bunch of additional things to enable modularity through using fragments too, which we'll visit a bit later in this article.

## Performance

In Relay, components will only re-render when the *exact fields* they're using change - with no work on your part! This is because each *fragment* will subscribe to updates only for the data it selects. 

That lets Relay optimize how your view is updated by default, ensuring that performance isn’t unnecessary degraded as your app grows. This is quite different to how other GraphQL clients operate. Don’t worry if that didn’t make much sense yet, we’ll show off some great examples of this below and how important it is for scalability.

With all that in mind, let’s start building our page!


> Relay doubles down on the concept of fragments, and uses them to enable co-location of data requirements, modularity and great performance.

# Building the page to render the blog post

Here’s a wireframe of what our page showing a single blog post will look like:


![](https://paper-attachments.dropbox.com/s_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1583924916777_image.png)


First, let’s think of how we’d approach this with getting all the data for this view through a single top-level query. A very reasonable query to fulfill the wireframe’s need might look something like this:

```graphql
    query BlogPostQuery($blogPostId: ID!) {
      blogPostById(id: $blogPostId) {
        author {
          firstName
          lastName
          avatarUrl
          shortBio
        }
        title
        coverImgUrl
        createdAt
        tags {
          slug
          shortName
        }
        body
        likedByMe
        likedBy(first: 2) {
          totalCount
          edges {
            node {
              firstName
              lastName
              avatarUrl
            }
          }
        }
      }
    }
```

One query to fetch all the data we need! Nice!

And, in turn, the structure of UI components might look something like this:

```jsx
    <BlogPost>
      <BlogPostHeader>
        <BlogPostAuthor>
          <Avatar />
        </BlogPostAuthor>
      </BlogPostHeader>
      <BlogPostBody>
        <BlogPostTitle />
        <BlogPostMeta>
          <CreatedAtDisplayer />
          <TagsDisplayer />
        </BlogPostMeta>
        <BlogPostContent />
        <LikeButton>
          <LikedByDisplayer />
        </LikeButton>
      </BlogPostBody>
    </BlogPost>
```

Let’s have a look at how we’d build this in Relay.


## Querying for data in Relay

In Relay, the root component rendering the blog post would typically look something like this:

```typescript
    // BlogPost.ts
    import * as React from "react";
    import { useLazyLoadQuery } from "react-relay/hooks";
    import { graphql } from "react-relay";
    import { BlogPostQuery } from "./__generated__/BlogPostQuery.graphql";
    import { BlogPostHeader } from "./BlogPostHeader";
    import { BlogPostBody } from "./BlogPostBody";
    
    interface Props {
      blogPostId: string;
    }
    
    export const BlogPost = ({ blogPostId }: Props) => {
      const { blogPostById } = useLazyLoadQuery<BlogPostQuery>(
        graphql`
          query BlogPostQuery($blogPostId: ID!) {
            blogPostById(id: $blogPostId) {
              ...BlogPostHeader_blogPost
              ...BlogPostBody_blogPost
            }
          }
        `,
        {
          variables: { blogPostId }
        }
      );
    
      if (!blogPostById) {
        return null;
      }
    
      return (
        <div>
          <BlogPostHeader blogPost={blogPostById} />
          <BlogPostBody blogPost={blogPostById} />
        </div>
      );
    };
```

Let’s break down what’s going on here, step by step.

```typescript
      const { blogPostById } = useLazyLoadQuery<BlogPostQuery>(
        graphql`
          query BlogPostQuery($blogPostId: ID!) {
            blogPostById(id: $blogPostId) {
              ...BlogPostHeader_blogPost
              ...BlogPostBody_blogPost
            }
          }
        `,
        {
          variables: { blogPostId }
        }
      );
```

The first thing to note is the React hook `useLazyLoadQuery` from Relay:
`const { blogPostById } = useLazyLoadQuery<BlogPostQuery>`. `useLazyLoadQuery` will start fetching `BlogPostQuery` as soon as the component renders.

For type safety, we’re annotating `useLazyLoadQuery` to explicitly state the type, `BlogPostQuery`, which we import from `./__generated__/BlogPostQuery.graphql`. That file is *automatically* generated (and kept in sync with changes to the query definition) by the Relay compiler, and has all the type information needed for the query - how the data coming back looks, and what variables the query wants.

> **Disclaimer time**!: As mentioned, `useLazyLoadQuery` will start fetching the query as soon as it renders. **However, note that** Relay actually doesn’t want you to lazily fetch data on render like this. Rather, Relay wants you to start loading your queries as soon as you can, like right when the user is clicking the link to a new page, instead of as the page renders. Why this is so important is talked about at length in this [blog post](https://reactjs.org/docs/concurrent-mode-suspense.html#approach-3-render-as-you-fetch-using-suspense), and in [this talk](https://www.youtube.com/watch?v=Tl0S7QkxFE4), which we warmly recommend you to read and watch.
> We’re still using the lazy load variant in this article though because it's a more familiar mental model for most people, and to keep things as simple and easy to follow as possible. But, please do note that as mentioned above this isn't how you should fetch your query data when building for real with Relay.

Next, we have our actual query:

```typescript
    graphql`
      query BlogPostQuery($blogPostId: ID!) {
        blogPostById(id: $blogPostId) {
          ...BlogPostHeader_blogPost
          ...BlogPostBody_blogPost
      }
    }`
```

Defining our query, there’s really not a whole lot left of the example query we demonstrated above. Other than selecting a blog post by its id, there’s only two more selections - the fragments for `<BlogPostHeader />` and `<BlogPostBody />` on `BlogPost`.  

> Notice that we don’t have to import the fragments we’re using. These are included automatically by the Relay compiler. More about that in a second.

Building your query by composing fragments together like this is very important. Another approach would be to let components define their own *queries* and be fully responsible for fetching their own data. While there are a few valid use cases for this, this comes with two major problems:

- A ton of queries are sent to your server instead of just one.
- Each component making their own query would need to wait until they’re actually rendered to start fetching their data. This means your view will likely load quite a lot slower than needed, as requests would probably be made in a waterfall.


> In Relay, we build UIs by composing components together. These components define what data they need themselves in an opaque way.

## How Relay enforces modularity

Here’s the mental model to keep in mind with the code above:


> As the `BlogPost` component, I only know I want to render two children components, `BlogPostHeader` and `BlogPostBody`. I don’t know what data they need (why would I? That’s their responsibility to know!).
> Instead, they’ve told me all the data they need is in a fragment called `BlogPostHeader_blogPost` and `BlogPostBody_blogPost` on the `BlogPost` GraphQL type. As long as I include their fragments in my query, I know I’m guaranteed to get the data they need, even though I don’t know any of the specifics. And when I have the data they need, I'm allowed to render them.

We build our UI by composing components that define their own data requirements *in isolation*. These components can then be composed together with other components with their own data requirements. However, no component really knows anything about what data other components need, other than from *what GraphQL source (type)* the component needs data. Relay takes care of the dirty work, making sure the right component gets the right data, and that all data needed is selected in the query that gets sent to the server. 

This allows you, the developer, to think in terms of *components* and *fragments* in isolation, while Relay handles all the plumbing for you.

Moving on!

## The Relay compiler knows all GraphQL code you’ve defined in your project

Notice that while the query is referencing two fragments, there’s no need to tell it _where_ or in what file those fragments are defined, or to import them manually to the query. This is because Relay enforces *globally unique* names for every fragment, so that the Relay compiler can *automatically* include the fragment definitions in any query that's being sent to the server.

Referencing fragment definitions by hand, another inconvenient, manual, potentially error-prone step, is no longer the developer’s responsibility with Relay.


> Using fragments tightly coupled to components allows Relay to hide the data requirements of a component from the outside world, which leads to great modularity and safe refactoring.

Finally, we get to rendering our results:

```typescript
      // Because we spread both fragments on this object
      // it's guaranteed to satisfy both `BlogPostHeader`
      // and `BlogPostBody` components.
      if (!blogPostById) {
        return null;
      }
    
      return (
        <div>
          <BlogPostHeader blogPost={blogPostById} />
          <BlogPostBody blogPost={blogPostById} />
        </div>
      );
```

Here we render `<BlogPostHeader />` and `<BlogPostBody />`. Looking carefully, you may see that we render both by passing them the `blogPostById` object. This is the object in the query where *we spread their fragments*. This is the way fragment data is transferred with Relay - passing the object where the fragment has been spread to the component using the fragment, which the component then uses to get the actual fragment data. Don't worry, Relay doesn't leave you hanging. Through the type system Relay will ensure that you're passing the _right_ object with the _right_ fragment spread on it. More on this in a bit.

Whew, that’s a few new things right there! But we’ve already seen and expanded on a number of things Relay does to help us - things that we would normally have to do manually for no additional gain.


> Following Relay’s conventions ensures that a component **cannot** be renderer without it having the data it asks for. This means you’ll have a hard time shipping broken code to production.

Let’s continue moving down the tree of components.


## Building a component using fragments

Here's the code for `<BlogPostHeader />`:

```typescript
    // BlogPostHeader.ts
    import * as React from "react";
    import { useFragment } from "react-relay/hooks";
    import { graphql } from "react-relay";
    import {
      BlogPostHeader_blogPost$key,
      BlogPostHeader_blogPost
    } from "./__generated__/BlogPostHeader_blogPost.graphql";
    import { BlogPostAuthor } from "./BlogPostAuthor";
    import { BlogPostLikeControls } from "./BlogPostLikeControls";
    
    interface Props {
      blogPost: BlogPostHeader_blogPost$key;
    }
    
    export const BlogPostHeader = ({ blogPost }: Props) => {
      const blogPostData = useFragment<BlogPostHeader_blogPost>(
        graphql`
          fragment BlogPostHeader_blogPost on BlogPost {
            title
            coverImgUrl
            ...BlogPostAuthor_blogPost
            ...BlogPostLikeControls_blogPost
          }
        `,
        blogPost
      );
    
      return (
        <div>
          <img src={blogPostData.coverImgUrl} />
          <h1>{blogPostData.title}</h1>
          <BlogPostAuthor blogPost={blogPostData} />
          <BlogPostLikeControls blogPost={blogPostData} />
        </div>
      );
    };
```    
> Our examples here only define one fragment per component, but a component could define _any number_ of fragments, on _any number_ of GraphQL types, including multiple fragments on the same type. 

Let’s break it down.

```typescript
    import {
      BlogPostHeader_blogPost$key,
      BlogPostHeader_blogPost
    } from "./__generated__/BlogPostHeader_blogPost.graphql";
```

We import two type definitions from the file `BlogPostHeader_blogPost.graphql`, autogenerated by the Relay compiler for us. 

The Relay compiler will extract the GraphQL fragment code from this file and generate type definitions from it. In fact, it will do that for *all* the GraphQL code you write in your project and use with Relay - queries, mutations, subscriptions and fragments. This also means that the types will be kept in sync with any change to the fragment definition automatically by the compiler.

`BlogPostHeader_blogPost` contains the type definitions for the fragment, and we pass that to `useFragment` (`useFragment` which we'll talk more about soon) ensuring that interaction with the data from the fragment is type safe. 

But what on earth is `BlogPostHeader_blogPost$key` on line 12 in `interface Props { … }`?! Well, it has to do with the type safety. You really _really_ don’t have to worry about this right now, but for the curious we’ll break it down anyway (the rest of you can just skip to the next heading):

That type definition ensures, via some dark type magic, that you can only pass the right object (where the `BlogPostHeader_blogPost` fragment has been spread) to `useFragment`, or you’ll have a type error at build time (in your editor!). As you can see, we take `blogPost` from props and pass it to `useFragment` as the second parameter. And if `blogPost` does not have the right fragment (`BlogPostHeader_blogPost`) spread on it, we’ll get a type error. 

It doesn't matter if another fragment with the _exact same_ data selections has been spread on that object, Relay will make sure it's the _exactly right_ fragment you want to use with `useFragment`. This is important, because it's another way Relay guarantees you can change your fragment definitions without any other component being affected implicitly.

Relay eliminates another source of potential errors: passing the _exact_ right object containing the _right_ fragment.

## You can only use data you’ve explicitly asked for

We define our fragment `BlogPostHeader_blogPost` on `BlogPost`. Notice that we explicitly select two fields for this component:

    - `title`
    - `coverImgUrl`

That’s because *we’re using these fields in this specific component*. This highlights another important feature of Relay - data masking. Even if `BlogPostAuthor_blogPost`, the next fragment we’re spreading, also selects `title` and `coverImgUrl` (meaning they *must* be available in the query on that exact place where we'll get them from), we won’t get access to them unless we *explicitly ask for them* via our own fragment. 

This is enforced both at the type level (the generated types won’t contain them) *and* at runtime - the values simply won’t be there even if you bypass your type system.

This can feel slightly weird at first, but it’s in fact another one of Relay’s safety mechanisms. If you know it’s impossible for other components to implicitly depend on the data you select, you can refactor your components without risking breaking other components in weird, unexpected ways. This is *great* as your app grows - again, every component and its data requirements become entirely self-contained.


> Enforcing that all data a component requires is explicitly defined means you can’t accidentally break your UI by removing a field selection from a query or fragment that some other component was depending on.

```typescript
      const blogPostData = useFragment<BlogPostHeader_blogPost>(
        graphql`
          fragment BlogPostHeader_blogPost on BlogPost {
            title
            coverImgUrl
            ...BlogPostAuthor_blogPost
            ...BlogPostLikeControls_blogPost
          }
        `,
        blogPost
      );
```

Here we're using the React hook `useFragment` to get the data for our fragment. `useFragment` knows how to take a _fragment definition_ (the one defined inside the `graphql` tag) and an object _where that fragment has been spread_ (`blogPost` here, which comes from `props`), and use that to get the data for this particular fragment.

Just to reiterate that point - no data for this fragment (`title`/`coverImgUrl`) will be available on `blogPost` coming from props - that data will only be available as we call `useFragment` with the fragment definition and `blogPost`, the object where the fragment has been spread.

And, just like before, we spread the fragments for the components we want to render - in this case, `BlogPostAuthor_blogPost` and `BlogPostLikeControls_blogPost` since we're renderering `<BlogPostAuthor />` and `<BlogPostLikeControls />`.

> For the curious: since fragments only describes what fields to select, `useFragment` won’t make an actual request for data to your GraphQL API. Rather, a fragment *must* end up in a query (or other GraphQL operation) at some point in order for its data to be fetched. With that said, Relay has some really cool features which will let you refetch a fragment all by itself. This is possible because Relay can _generate queries automatically_ for you to refetch specific GraphQL objects by their `id`. Anyway, we digress...


> Also, if you know Redux, you can liken `useFragment` to a selector that lets you grab only what you need from the state tree.

```typescript
      return (
        <div>
          <img src={blogPostData.coverImgUrl} />
          <h1>{blogPostData.title}</h1>
          <BlogPostAuthor blogPost={blogPostData} />
          <BlogPostLikeControls blogPost={blogPostData} />
        </div>
      );
```

We then render the data we explicitly asked for (`coverImgUrl` and `title`), and pass the data for the two children components along so they can render. Notice again that we pass the object to the components where we spread their fragments, which is at the root of the fragment `BlogPostHeader_blogPost` this component defines and uses.

## How Relay ensures you stay performant

When you use fragments, each fragment will subscribe to updates only for the data it’s actually using. This means that our `<BlogPostHeader />` component above will only re-render by itself if `coverImgUrl` or `title` on the specific blog post it’s rendering is updated. If  `BlogPostAuthor_blogPost` selects other fields and those update, this component still won’t re-render. Changes to data is subscribed to *at the fragment level*.

This may sound a bit confusing and perhaps not that useful at first, but it’s incredibly important for performance. Let’s take a deeper look at this by contrasting it to how this type of thing is typically done in when dealing with GraphQL data on the client.


> With Relay, only the components using the data that was updated will re-render when data updates.

## Where does the data come from in your view? Contrasting Relay to other frameworks

All data you use in your views must originate from an actual operation that gets data from the server, like a query. You define a query, have your framework fetch it from the server, and then render whatever components you want in your view, passing down the the data they need. The source of the data for most GraphQL frameworks is *the query*. Data flows from the query down into components. Here’s an example of how that’s typically done in other GraphQL frameworks (arrows symbolize how data flows):


![](https://paper-attachments.dropbox.com/s_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1584360131172_image.png)

> Note: framework data store is what’s usually referred to as the cache in a lot of frameworks. For this article, assume that `"framework data store" === cache`.

The flow looks something like:

1. `<Profile />` makes the `query ProfileQuery` and a request is issued to the GraphQL API
2. The response is stored in some fashion in a framework-specific data store (read: cache)
3. The data is delivered to the view for rendering
4. The view then continues to pass down pieces of the data to whatever descendant components needs it (`Avatar`, `Name`, `Bio`, etc.). Finally,  your view is rendered


## How Relay does it

Now, Relay does this quite differently. Let’s look at how this illustration looks for Relay:


![](https://paper-attachments.dropbox.com/s_AECAC5D1357DAAD0F680E7CAD047ACE357666A78B0A066ED11712B9AC877E33E_1584360226714_image.png)


What’s different?

- Most of the initial flow is the same - the query is issued to the GraphQL API and the data ends up in the framework data store. But then things start to differ. 
- Notice that all components which use data get it *directly from the* *data store (cache)*. This is due to Relay’s deep integration with fragments - in your UI, each fragment gets its own data from the framework data store directly, and *does* *not* rely on the actual data being passed down to it from the query where its data originated.
- The arrow is gone from the query component down to the other components. We’re still passing some information from the query to the fragment that it uses to look up the data it needs from the data store. But we’re passing no real data to the fragment, all the real data is retrieved by the fragment itself from the data store.

So, that’s quite in depth into how Relay and other GraphQL frameworks tend to work. Why should you care about this? Well, this setup enables some pretty neat features.


> Other frameworks typically use a query as the source of data, and rely on you passing the data down the tree to other components. Relay flips this around, and lets each component take the data it needs from the data store itself.

## Performance for free

Think about it: When the query is the source of the data, any update to the data store that affects any data that query has *forces a re-render for the component holding the query*, so the updated data can flow down to any component that might use it. This means updates to the data store causes re-renders that must cascade through any number of layers of components that don’t really have anything to do with the update, other than taking data from parent components in order to pass on to children components. 

Relay's approach of each component getting the data it needs from the store directly, and subscribing to updates only for the exact data it uses, ensures that we stay performant even as our app grows in size and complexity.

This is also important when using subscriptions. Relay makes sure that updated data coming in from the subscription only causes re-renders of the components actually using that updated data.

> Using a `Query` as the source of data means your entire component tree will be forced to re-render when the GraphQL cache is updated.

## Modularity and isolation means you can safely refactor

Removing the responsibility from the developer of routing the data from the query down to whichever component actually *needs* said data also removes another chance for developers to mess things up. There’s simply *no way* to accidentally (or worse, intentionally) depend on data that should just be passing through down the component tree if you can't access it. Relay again makes sure it does the heavy work for you when it can.

> Using Relay and its fragment-first approach means it's really hard to mess up the data flow in a component tree.

It should of course be noted though that most of the cons of the “query as the source of data” approach can be somewhat mitigated by old fashioned manual optimization - `React.memo`, `shouldComponentUpdate` and so on. But that’s both potentially a performance problem in itself, and also prone to mistakes (the more fiddly a task, the more likely humans are to eventually mess it up). Relay on the other hand will make sure you stay performant without needing to think about it.

> Each component receiving its own data from the cache also enables some really cool advanced features of Relay, like partially rendering views with the data that’s already available in the store while waiting for the full data for the view to come back. 

## Summarizing fragments

Let’s stop here for a bit and digest what type of work Relay is doing for us:

- Through the type system, Relay is making sure this component *cannot* be rendered without the *exact* right object from GraphQL, containing its data. One less thing we can mess up.
- Since each component using fragments will only update if the exact data it uses updates, updates to the cache is performant by default in Relay.
- Through type generation, Relay is ensuring that any interaction with this fragment's data is type safe. Worth highlighting here is that type generation is a core feature of the Relay compiler.

Relay’s architecture and philosophy takes advantage of how much information is available about your components to the computer, from the data dependencies of components, to the data and its types offered by the server. It uses all this and more to do all sorts of work that normally we - the developers who have *plenty* to do already - are required to deal with.

> It's easy to underestimate how quickly views become complex. Complexity and performance is handled by default through the conventions Relay force you to follow.

This brings some real power to you as a developer:

- You can build composable components that are almost completely isolated.
- Refactoring your components will be fully safe, and Relay will ensure you’re not missing anything or messing this up.

The importance of this once you start building a number of reusable components cannot be overstated. It’s *crucial* for developer velocity to have refactoring components used in large parts of the code base be safe.


> As your app grows, the ease and safety of refactoring becomes crucial to continue moving fast.

# Wrapping up our introduction to Relay

We’ve covered a lot of ground in this article. If you take anything with you, let it be that Relay *forces* you to build scalable, performant, type safe applications that will be easy and safe to maintain and refactor.

Relay really does do your dirty work for you, and while a lot of what we’ve shown will be possible to achieve through heroic effort with other frameworks, we hope we’ve shown the powerful benefits that *enforcing* these patterns can bring. Their importance cannot be overstated.


## A remarkable piece of software

Relay is really a remarkable piece of software, built from the blood, sweat, tears, and most importantly - experience and deep insight - of shipping and maintaining products using GraphQL for a long time.

Even though this article is pretty long and fairly dense, we've barely scratched the surface of what Relay can do. Let's end this article with a list detailing some of what more Relay can do that we haven't covered in this article:

- Mutations with optimistic and complex cache updates
- Subscriptions
- Fully integrated with (and heavily leveraging) Suspense and Concurrent Mode - ready for the next generation of React
- Use Relay to manage your local state through Relay, enjoying the general benefits of using Relay also for local state management (like integration with Suspense and Concurrent Mode!)
- Streaming list results via `@stream`
- Deferring parts of the server response that might take a long time to load via `@defer`, so the rest of the UI can render faster
- Automatic generation of queries for refetching fragments and pagination
- Complex cache management; control how large the cache is allowed to get, and if data for your view should be resolved from the cache or the network (or both, or first the cache and then the network)
- A stable, mature and flexible cache that _Just Works (tm)_
- Preload queries for new views as soon as the user indicates navigation is about to happen
_ Partially render views with any data already available in the store, while waiting for the query data to arrive
- Define arguments for fragments (think like props for a component), taking composability of your components to the next level
- Teach Relay more about how the data in your graph is connected than what can be derived from your schema, so it can resolve more data from the cache (think "these top-level fields with these variables resolve the same User")

This article ends here, but we really encourage you to go on and read the article on pagination in Relay. Pagination in Relay bring together the powerful features of Relay in a beautiful way, showcasing just how much automation and what incredible DX is possible when you let a framework do all the heavy lifting. [Read it here](https://dev.to/zth/pagination-with-minimal-effort-in-relay-gl4)

Here’s a few other articles you can continue with too:

- [The magic of the `Node` interface](https://dev.to/zth/the-magic-of-the-node-interface-4le1). An article about the `Node` interface, globally unique IDs and what power those things bring.
- [Connection based pagination](https://dev.to/zth/connection-based-pagination-in-graphql-2588). An introduction to why doing connection based pagination is a good idea.

Thank you for reading!


# Special thanks

Many thanks to Xavier Cazalot, Arnar Þór Sveinsson, Jaap Frolich, Joe Previte, Stepan Parunashvili, and Ben Sangster for thorough feedback on the drafts of this article!