Part 6: Image CDN
Gatsby has best-in-class image support with its
gatsby-plugin-image feature. With it you can easily add responsive, optimized images to sites in all modern formats. Traditionally, images were downloaded and transformed to enable this behavior. Image CDN solves this by skipping image processing during the build, and instead deferring and offloading it to a dedicated image CDN. Visitors still get images in the most optimized formats such as AVIF and WebP, but site builds complete in a fraction of the time.
By the end of this part of the tutorial, you will be able to:
- Add Image CDN support to your source plugin
- Use Image CDN with
gatsby-plugin-imagein your example site
Gatsby’s Image CDN feature can be added to any Gatsby source plugin. We recommend using it over manual file downloading for the reasons above. As long as your API gives back a URL to an image, you should be able to implement the required code. Basically, for Image CDN to work you need two things:
- A GraphQL root node type that implements the
- During node creation for that GraphQL node type, certain fields must exist on the node to match what
In Part 3 you learned that root node types need to implement the
Node interface. Similarly to
RemoteFile is also provided by Gatsby itself and will handle all the complicated pieces of Image CDN behind the scenes.
Pro tip: Gatsby’s Image CDN feature is smart enough to work on all platforms, even if no CDN provider like on Gatsby Cloud or Netlify is available. In those cases (including locally on your computer) it automatically falls back to processing images during the build. This won’t give users a build improvement but things on the frontend will still behave the same and builds won’t fail.
RemoteFile interface has the following shape:
For node types implementing
RemoteFile this means:
- Always required are
publicUrl(the url to the image/file),
publicUrlwill be defined through
urlduring node creation.
gatsbyImagecan be null. This is because the
RemoteFileinterface can also handle assets other than images, like PDFs.
For node types that are images this means:
height are mandatory.
gatsbyImage will be provided by Gatsby. They are GraphQL resolvers relying on the existing data on the GraphQL node. You’ll use
gatsbyImage later to get your data for the
<GatsbyImage /> comopnent.
Here’s an example of a GraphQL root node that implements
RemoteFile and creates nodes with all required fields for images:
Schema customization to implement
ImageAssetnode with all required fields:
As you can see the
ImageAsset node holds all required fields but you can also add your own additional, arbitrary fields (like
alt shown in the example). Once
ImageAsset is created, you’ll be able to call
resize on these GraphQL nodes and use Image CDN.
The URL you provide to the
url field should link to the image version with the highest resolution, so if e.g. your API can provide image URLs in different sizes, pick the one with the best resolution.
One field that hasn’t been mentioned yet is the
<GatsbyImage /> component supports displaying a placeholder while the image loads. You can tell Image CDN to use your
placeholderUrl to generate said placeholder. If your API supports returning different sized images through URL segments or URL params, you can place
%height% into the URL. This tutorial uses Unsplash as it supports dynamically resizing images and thus both are used with the
w query param. Alternatively, you could also provide the smallest possible image available from your API to this field.
Are width and height missing from the API response? Not every API returns width, height, and mimeType for an image. You can use
probe-image-size to get these information from your remote URL.
probe-image-size returns a Promise so you’ll need to
await its result. You could use it something like this:
Time to apply your theoretical knowledge about Image CDN to your own plugin.
You’ll create a new root node called
Asset through a
createAssetNode utility. You can think of it as a more specialized version of the
nodeBuilder utility, only responsible for creating nodes that should become
Asset and hence Image CDN capable. Creating a separate
Asset type will also make schema customization in the next task easier.
plugin/src/constants.tsand add a new node type:
plugin/src/source-nodes.ts. Add the type imports for
IPostImageInput, create a shell for
createAssetNodeat the end of the file:
gatsbyApito call the various node helpers but
datamust be in the shape of
IPostImageInput. This TypeScript type is identical to the
imageobject shape inside each post in
Create the function body for
createAssetNodeby following what
TypeScript should complain about missing fields on
These are exactly the fields that are required for image assets.
Add the missing fields to the node:
And that’s it, you can create
Assetnodes now! In the next task you’ll actually use
So far your
createAssetNode utility isn’t doing anything. You’ll need to use it inside the
nodeBuilder utility to add an additional
image field to
Post nodes. However, this will only work once you have successfully implemented the second requirement of Image CDN: That
Asset implements the
You’ll implement the
RemoteFile interface for
Asset and make it a root node. Then you’ll create a foreign-key relationship between
Asset and the
image field on
plugin/src/create-schema-customization.ts. Change the name of
Assetand implement both
createAssetNodecreates will be GraphQL root nodes now.
Type builder example
If you’re not using the SDL syntax but type builders, you’d add it like this:
Create a foreign-key relationship between
If you remember from Part 3, the default behavior of
@linkis to use the
idfrom the target node. Keep that in mind for the following instructions.
plugin/src/source-nodes.tsfile and add a return statement to the
createAssetNodefunction. Return the generated
A node of type
Postshould have the generated
imagefield. Because only posts can have images, you can conditionally add data to the node if certain conditions are met like this:
some-idstring should be replaced by the
Assetid of course. Since
id, you can use its result:
develop:sitescript and open GraphiQL at
http://localhost:8000/___graphql. Run the following query:
You should get a result back like this:
It works! Note:
<long-string>is added above to make things easier to read. If you’re seeing an error, stop the
yarn clean:siteand retry
In the next task you’ll be able to use the result from
gatsbyImageinside your pages.
gatsby-plugin-image you use the
gatsbyImageData GraphQL field to access the necessary data. With Image CDN this name changes to
gatsbyImage — you’ve learned this in the last task. The only relevant difference between
gatsbyImage is that the latter requires a
Refer to the
gatsby-plugin-image how-to for instructions on its usage as this tutorial won’t go into details about that.
imageto the GraphQL query:
Import the necessary
gatsby-plugin-imagehelpers and components and use them with
http://localhost:8000/post-1/. You should see a dog image on the page:
Magnificent! Your posts now have photos of cute dogs.
Take a moment to think back on what you’ve learned so far. Challenge yourself to answer the following questions from memory:
- What are the two steps required to implement Image CDN in a source plugin?
- What types of files can
- What are the mandatory fields that
- By using Image CDN you can offload the heavy image generation to dedicated providers, giving users of your source plugin great build performance.
- GraphQL root node types of your plugin that represent files and/or images should implement the
RemoteFileinterface and have all required fields on their node.
- You can use
gatsbyImagein your GraphQL result together with
gatsby-plugin-imagelike you’re used to.
Share Your Feedback!
Our goal is for this tutorial to be helpful and easy to follow. We’d love to hear your feedback about what you liked or didn’t like about this part of the tutorial.
Use the “Was this doc helpful to you?” form at the bottom of this page to let us know what worked well and what we can improve.
In Part 7 advanced topics like Content Sync, testing, debugging, and more will be explained.Continue to Part 7