gatsby-source-contentful
Table of contents
- gatsby-source-contentful
Install
npminstall gatsby-source-contentful gatsby-plugin-imageSetup Instructions
To get setup quickly with a new site and have Netlify do the heavy lifting,deploy a new Gatsby Contentful site with just a few clicks on netlify.com.
How to use
First, you need a way to pass environment variables to the build process, so secrets and other secured data aren’t committed to source control. We recommend usingdotenv which will then expose environment variables.Read more aboutdotenv and using environment variables here. Then we canuse these environment variables and configure our plugin.
Restrictions and limitations
This plugin has several limitations, please be aware of these:
At the moment, fields that do not have at least one populated instance will not be created in the GraphQL schema. This can break your site when field values get removed. You may workaround with an extra content entry with all fields filled out.
When using reference fields, be aware that this source plugin will automatically create the reverse reference. You do not need to create references on both content types.
When working with environments, your access token has to have access to your desired environment and the
masterenvironment.Using the preview functionality might result in broken content over time, as syncing data on preview is not officially supported by Contentful. Make sure to regularly clean your cache when using Contentful’s preview API.
The following content type names are not allowed:
entity,referenceThe following field names are restricted and will be prefixed:
children,contentful_id,fields,id,internal,parent,The Plugin has a dependency on
gatsby-plugin-imagewhich itself has dependencies. CheckDisplaying responsive image with gatsby-plugin-image to determine which additional plugins you’ll need to install.
Using Delivery API
// In your gatsby-config.jsmodule.exports={plugins:[{resolve:`gatsby-source-contentful`,options:{spaceId:`your_space_id`,// Learn about environment variables: https://gatsby.dev/env-varsaccessToken: process.env.CONTENTFUL_ACCESS_TOKEN,},},`gatsby-plugin-image`,],}Using Preview API
// In your gatsby-config.jsmodule.exports={plugins:[{resolve:`gatsby-source-contentful`,options:{spaceId:`your_space_id`,// Learn about environment variables: https://gatsby.dev/env-varsaccessToken: process.env.CONTENTFUL_ACCESS_TOKEN,host:`preview.contentful.com`,},},`gatsby-plugin-image`,],}Offline
If you don’t have internet connection you can addexport GATSBY_CONTENTFUL_OFFLINE=true to tell the plugin to fallback to the cached data, if there is any.
Configuration options
spaceId [string][required]
Contentful space ID
accessToken [string][required]
Contentful delivery API key, when using the Preview API use your Preview API key
host [string][optional] [default:'cdn.contentful.com']
The base host for all the API requests, by default it’s'cdn.contentful.com', if you want to use the Preview API set it to'preview.contentful.com'. You can use your own host for debugging/testing purposes as long as you respect the same Contentful JSON structure.
environment [string][optional] [default: ‘master’]
The environment to pull the content from, for more info on environments check out thisGuide.
downloadLocal [boolean][optional] [default:false]
Downloads and cachesContentfulAsset’s to the local filesystem. Allows you to query aContentfulAsset’slocalFile field, which is not linked to Contentful’s CDN. SeeDownload assets for static distribution for more information on when and how to use this feature.
localeFilter [function][optional] [default:() => true]
Possibility to limit how many locales/nodes are created in GraphQL. This can limit the memory usage by reducing the amount of nodes created. Useful if you have a large space in Contentful and only want to get the data from one selected locale.
For example, to filter locales on only germanylocaleFilter: locale => locale.code === 'de-DE'
List of locales and their codes can be found in Contentful app -> Settings -> Locales
proxy [object][optional] [default:undefined]
Axios proxy configuration. See theaxios request config documentation for further information about the supported values.
useNameForId [boolean][optional] [default:true]
Use the content’sname when generating the GraphQL schema e.g. a content type called[Component] Navigation bar will be namedcontentfulComponentNavigationBar.
When set tofalse, the content’s internal ID will be used instead e.g. a content type with the IDnavigationBar will be calledcontentfulNavigationBar.
Using the ID is a much more stable property to work with as it will change less often. However, in some scenarios, content types’ IDs will be auto-generated (e.g. when creating a new content type without specifying an ID) which means the name in the GraphQL schema will be something likecontentfulC6XwpTaSiiI2Ak2Ww0oi6qa. This won’t change and will still function perfectly as a valid field name but it is obviously pretty ugly to work with.
If you are confident your content types will have natural-language IDs (e.g.blogPost), then you should set this option tofalse. If you are unable to ensure this, then you should leave this option set totrue (the default).
pageLimit [number][optional] [default:1000]
Number of entries to retrieve from Contentful at a time. Due to some technical limitations, the response payload should not be greater than 7MB when pulling content from Contentful. If you encounter this issue you can set this param to a lower number than 100, e.g50.
assetDownloadWorkers [number][optional] [default:50]
Number of workers to use when downloading Contentful assets. Due to technical limitations, opening too many concurrent requests can cause stalled downloads. If you encounter this issue you can set this param to a lower number than 50, e.g 25.
contentfulClientConfig [object][optional] [default:{}]
Additional config which will get passed toContentfuls JS SDK.
Use this with caution, you might override values this plugin does set for you to connect to Contentful.
enableTags [boolean][optional] [default:false]
Enable the newtags feature. This will disallow the content type nametags till the next major version of this plugin.
Learn how to use them at theContentful Tags section.
contentTypeFilter [function][optional] [default: () => true]
Possibility to limit how many contentType/nodes are created in GraphQL. This can limit the memory usage by reducing the amount of nodes created. Useful if you have a large space in Contentful and only want to get the data from certain content types.
For example, to exclude content types starting with “page”contentTypeFilter: contentType => !contentType.sys.id.startsWith('page')
typePrefix [string][optional] [default:Contentful]
Prefix for the type names created in GraphQL. This can be used to avoid conflicts with other plugins, or if you want more than one instance of this plugin in your project. For example, if you set this toBlog, the type names will beBlogAsset andallBlogAsset.
How to query for nodes
Two standard node types are available from Contentful:Asset andContentType.
Asset nodes will be created in your site’s GraphQL schema undercontentfulAsset andallContentfulAsset.
ContentType nodes are a little different - their exact name depends on what you called them in your Contentful data models. The nodes will be created in your site’s GraphQL schema undercontentful${entryTypeName} andallContentful${entryTypeName}.
In all cases querying for nodes likecontentfulX will return a single node, and nodes likeallContentfulX will return all nodes of that type.
Query for all nodes
You might query forall of a type of node:
{allContentfulAsset{nodes{contentful_idtitledescription}}}You might do this in yourgatsby-node.js using Gatsby’screatePages Node API.
Query for a single node
To query for a singleimage asset with the title'foo' and a width of 1600px:
exportconst assetQuery= graphql` { contentfulAsset(title: { eq: "foo" }) { contentful_id title description file { fileName url contentType details { size image { height width } } } } }`To query for a singleCaseStudy node with the short text propertiestitle andsubtitle:
{contentfulCaseStudy(filter:{title:{eq: 'bar'}}){titlesubtitle}}You might query for asingle node inside a component in yoursrc/components folder, usingGatsby’sStaticQuery component.
A note about LongText fields
On Contentful, a “Long text” field uses Markdown by default. The field is exposed as an object, while the raw Markdown is exposed as a child node.
{contentfulCaseStudy{body{body}}}Unless the text is Markdown-free, you cannot use the returned value directly. In order to handle the Markdown content, you must use a transformer plugin such asgatsby-transformer-remark. The transformer will create achildMarkdownRemark on the “Long text” field and expose the generated html as a child node:
{contentfulCaseStudy{body{childMarkdownRemark{html}}}}You can then insert the returned HTML inline in your JSX:
<divclassName="body"dangerouslySetInnerHTML={{__html: data.contentfulCaseStudy.body.childMarkdownRemark.html,}}/>Duplicated entries
When Contentful pulls the data, all localizations will be pulled. Therefore, if you have a localization active, it will duplicate the entries. Narrow the search by filtering the query withnode_locale filter:
{allContentfulCaseStudy(filter:{node_locale:{eq:"en-US"}}){edges{node{idslugtitlesubtitlebody{body}}}}}Query for Assets in ContentType nodes
More typically yourAsset nodes will be mixed inside of yourContentType nodes, so you’ll query them together. All the same formatting rules forAsset andContentType nodes apply.
To getall theCaseStudy nodes withShortText fieldsid,slug,title,subtitle,LongText fieldbody andheroImage asset field, we useallContentful${entryTypeName} to return all instances of thatContentType:
{allContentfulCaseStudy{edges{node{idslugtitlesubtitlebody{body}heroImage{titledescriptiongatsbyImageData(layout:CONSTRAINED)# Further below in this doc you can learn how to use these response images}}}}}More on Queries with Contentful and Gatsby
It is strongly recommended that you take a look at how data flows in a real Contentful and Gatsby application to fully understand how the queries, Node.js functions and React components all come together. Check out the example site atusing-contentful.gatsbyjs.org.
Displaying responsive image with gatsby-plugin-image
To use it:
- Install the required plugins:
npminstall gatsby-plugin-image gatsby-plugin-sharp- Add the plugins to your
gatsby-config.js:
module.exports={plugins:[`gatsby-plugin-sharp`,`gatsby-plugin-image`,// ...etc],}- You can then query for image data using the new
gatsbyImageDataresolver:
{allContentfulBlogPost{nodes{heroImage{gatsbyImageData(layout:FULL_WIDTH)}}}}- Your query will return a dynamic image. Check thedocumentation of gatsby-plugin-image to learn how to render it on your website.
Check theReference Guide of gatsby-plugin-image to get a deeper insight on how this works.
Building images on the fly viauseContentfulImage
WithuseContentfulImage and the URL to the image on the Contentful Image API you can create dynamic images on the fly:
import{ GatsbyImage}from"gatsby-plugin-image"import*as Reactfrom"react"import{ useContentfulImage}from"gatsby-source-contentful/hooks"constMyComponent=()=>{const dynamicImage=useContentfulImage({image:{url:"//images.ctfassets.net/k8iqpp6u0ior/3BSI9CgDdAn1JchXmY5IJi/f97a2185b3395591b98008647ad6fd3c/camylla-battani-AoqgGAqrLpU-unsplash.jpg",width:2000,height:1000,},})return<GatsbyImage image={dynamicImage}/>}On-the-fly image options:
This hook accepts the same parameters as thegatsbyImageData field in your GraphQL queries. They are automatically translated to the proper Contentful Image API parameters.
Here are the most relevant ones:
- width: maximum 4000
- height: maximum 4000
- toFormat: defaults to the actual image format
- jpegProgressive: set to
progressiveto enable - quality: between 1 and 100
- resizingBehavior:https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/change-the-resizing-behavior
- cropFocus:https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/specify-focus-area
- background: background color in format
rgb:9090ff - cornerRadius:https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/crop-rounded-corners-&-circle-elipsis
Contentful Tags
You need to set theenableTags flag totrue to use this new feature.
List available tags
This example lists all available tags. The sorting is optional.
queryTagsQuery{allContentfulTag(sort:{fields:contentful_id}){nodes{namecontentful_id}}}Filter content by tags
This filters content entries that are tagged with thenumberInteger tag.
queryFilterByTagsQuery{allContentfulNumber(sort:{fields:contentful_id}filter:{metadata:{tags:{elemMatch:{contentful_id:{eq:"numberInteger"}}}}}){nodes{titleinteger}}}Contentful Rich Text
Rich Text feature is supported in this source plugin, you can use the following query to get the JSON output:
Note: In our example Content Model the field containing the Rich Text data is calledbodyRichText. Make sure to use your field name within the Query instead ofbodyRichText
Query Rich Text content and references
querypageQuery($id:String!){contentfulBlogPost(id:{eq:$id}){titleslug# This is the rich text field, the name depends on your field configuration in ContentfulbodyRichText{rawreferences{...onContentfulAsset{# You'll need to query contentful_id in each referencecontentful_id__typenamefixed(width:1600){widthheightsrcsrcSet}}...onContentfulBlogPost{contentful_id__typenametitleslug}}}}}Rendering
import{BLOCKS,MARKS}from"@contentful/rich-text-types"import{ renderRichText}from"gatsby-source-contentful/rich-text"constBold=({ children})=><spanclassName="bold">{children}</span>constText=({ children})=><pclassName="align-center">{children}</p>const options={renderMark:{[MARKS.BOLD]:text=><Bold>{text}</Bold>,},renderNode:{[BLOCKS.PARAGRAPH]:(node, children)=><Text>{children}</Text>,[BLOCKS.EMBEDDED_ASSET]:node=>{return(<><h2>Embedded Asset</h2><pre><code>{JSON.stringify(node,null,2)}</code></pre></>)},},}functionBlogPostTemplate({ data}){const{ bodyRichText}= data.contentfulBlogPostreturn<div>{bodyRichText&&renderRichText(bodyRichText, options)}</div>}Note: Thecontentful_id and__typename fields must be queried on rich-text references in order for therenderNode to receive the correct data.
Embedding an image in a Rich Text field
Import
import{ renderRichText}from"gatsby-source-contentful/rich-text"GraphQL
mainContent{rawreferences{...onContentfulAsset{contentful_id__typenamegatsbyImageData}}}Options
const options={renderNode:{"embedded-asset-block":node=>{const{ gatsbyImageData}= node.data.targetif(!gatsbyImageData){// asset is not an imagereturnnull}return<GatsbyImageimage={gatsbyImageData}/>},},}Render
<article>{blogPost.mainContent&&renderRichText(blogPost.mainContent, options)}</article>Check out the examples at@contentful/rich-text-react-renderer.
Download assets for static distribution
When you setdownloadLocal: true in your config, the plugin will download and cache Contentful assets to the local filesystem.
There are two main reasons you might want to use this option:
- Avoiding the extra network handshake required to the Contentful CDN for images hosted there
- Gain more control over how images are processed or rendered (ie, providing AVIF with gatsby-plugin-image)
The default setting for this feature isfalse, as there are certain tradeoffs for using this feature:
- All assets in your Contentful space will be downloaded during builds
- Your build times and build output size will increase
- Bandwidth going through your CDN will increase (since images are no longer being served from the Contentful CDN)
- You will have to change how you query images and which image fragments you use.
Enable the feature with thedownloadLocal: true option.
// In your gatsby-config.jsmodule.exports={plugins:[{resolve:`gatsby-source-contentful`,options:{spaceId:`your_space_id`,// Learn about environment variables: https://gatsby.app/env-varsaccessToken: process.env.CONTENTFUL_ACCESS_TOKEN,downloadLocal:true,},},],}Updating Queries for downloadLocal
When using thedownloadLocal setting, you’ll need to update your codebase to be working with the locally downloaded images, rather than the default Contentful Nodes. Query aContentfulAsset’slocalFile field in GraphQL to gain access to the common fields of thegatsby-source-filesystemFile node. This is not a Contentful node, so usage forgatsby-plugin-image is different:
queryMyQuery{# Example is for a `ContentType` with a `ContentfulAsset` field# You could also query an asset directly via# `allContentfulAsset { edges{ node { } } }`# or `contentfulAsset(contentful_id: { eq: "contentful_id here" } ) { }`contentfulMyContentType{myContentfulAssetField{# Query for locally stored file(e.g. An image) - `File` nodelocalFile{# Use `gatsby-plugin-image` to create the image datachildImageSharp{gatsbyImageData(formats:AVIF)}}}}}Note: This feature downloads any file from aContentfulAsset node thatgatsby-source-contentful provides. They are all copied over from./cache/gatsby-source-filesystem/ to the sites build location./public/static/.
For any troubleshooting related to this feature, first try clearing your./cache/ directory.gatsby-source-contentful will acquire fresh data, and allContentfulAssets will be downloaded and cached again.
Sourcing From Multiple Contentful Spaces
To source from multiple Contentful environments/spaces, add another configuration forgatsby-source-contentful ingatsby-config.js:
// In your gatsby-config.jsmodule.exports={plugins:[{resolve:`gatsby-source-contentful`,options:{spaceId:`your_space_id`,accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,},},{resolve:`gatsby-source-contentful`,options:{spaceId:`your_second_space_id`,accessToken: process.env.SECONDARY_CONTENTFUL_ACCESS_TOKEN,},},],}