Maybe it's because I'm relatively new to Jamstack but I am finding it difficult to get Strapi and Gatsby to play well together out of the box. I burned a lot of hours trying to figure out how to get missing components to show up in GraphQL queries, so I'm sharing what worked for me here in case anyone else is desperately searching for the same answers.

The following is based on the latest versions of Node.js (17.6.0) and NPM (8.5.2) at the time of this writing.

Pre-requisites

The Problem

You are using the gatsby-source-strapi plugin to create queries and are succuessfully retrieving a top-level responses. But! Not all your fields are being returned, or, in some cases, they are being returned but only show an id value. For me, it was single and repeatable component fields. It turns out these are called deeply nested fields, which call for special filters.

The Solution

In some cases, simply sending the query populate=* to Strapi from Gatsby will do the trick. This is the simplest solution for the cases in which it works - it seems to be enough for some simple elements. You can update your strapiConfig to include additional information for your collection and single types to pass this argument.

First Try: Gatsby Quick Fix

In gatsby-config.js:

const strapiConfig = {
  // ...
  collectionTypes: [
    {
      name: "your_type_name_here",
      endpoint: "api/your_type_name_endpoint_here",
      api: {
        qs: {
          populate: "*"
        }
      }
    }
  ],
  singleTypes: []
}

However, I soon realized this wasn't fixing most of my use cases. Instead, I needed to go to Strapi and edit the Controller for my Content Type to populate and return the data I needed in my GraphQL queries.

Legend has it that this fix used to work in Version 3 because Strapi would automatically fully populate its query when that parameter was passed through, but is no longer supported for reasons I do not understand, considering the entire point of Strapi is to quickly generate accessible APIs.

Root Issue: Strapi Fix

The root issue is that Strapi does not populate too-deeply nested components in the API. You can manually fix this using Strapi controllers. You can populate media, components, and dynamic zones by manually specifying them. There were also code snippets that claimed to automatically populate all fields, but none of them worked for me. If I find any, I will update this post to include because it would be much easier to manage when you are still actively developing your API by adding, renaming, or changing fields.

Strapi Configuration

Notice: This code is to give you the pattern you need, and will not work if you simply copy-paste it into your project!

Look out for your-type-name and replace it with your type. For me, it was site. In the original example, it was layout. Next, look out for your-field and sub-field and make sure it follows the same pattern as your type's fields.

File to edit: src\api\your-type-name\controllers\your-type-name.js

The code:

'use strict';

/**
 *  your-type-name controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::your-type-name.your-type-name', ({ strapi }) => ({
    async find(ctx) {
        const { query } = ctx;

        const entity = await strapi.entityService.findMany('api::your-type-name.your-type-name', {
            ...query,
            populate: {
                your-field: {
                    populate: {
                        sub-field: true
                    }
                },
            },
        });
        const sanitizedEntity = await this.sanitizeOutput(entity, ctx);

        return this.transformResponse(sanitizedEntity);
    }
}));

The populate, sub-field pattern can be repeated for further nested fields. For example:

populate: {
  your-field: {
    populate: {
      sub-field: {
        populate: {
         sub-sub-field: true
        }
      }
    }
  },
},

And you can add as many fields as you need to the list, for example:

populate: {
  your-field: {
    populate: {
      sub-field: true
    }
  },
  your-field-2: {
    populate: {
      sub-field-2: true
    }
  },
},

I had a hard time tracking these answers down so I wanted to collect them in one easy place for the next Jamstack beginner trying to get their Strapi-Gatsby static site working.

How to Troubleshoot

You can use the Strapi GraphQL Playground located at http://localhost:1337/graphql to identify the field structures for populating in the Strapi controller.

You can use the Gatsby GraphiQL Tool located at http://localhost:8000/__graphql to test what information is being exposed to your Gatsby GraphQL queries.

Don't forget to stop both servers, clear their caches, and restart them if it seems like something should be working but isn't immediately after a change.