MDX 2 Breaking changes and gatsby-plugin-mdx v4 (Slug)
If you’re upgrading to v4 of gatsby-plugin-mdx you’ll likely run into errors. Both MDX 2 and v4 of the plugin are major releases and inline with semantic versioning guidelines, breaking changes are to be expected.
Both Gatsby and MDX have documented the changes and you can find more information about the changes on the following links.
Breaking Changes to Slug
In this post I’ll only be covering the changes to the slug
field. This change may only be relevant if you’re using
mdx.slug
to form routes using either
createPage or
collection routes with
File System Route API.
The Error
ERROR #85923 GRAPHQL
There was an error in your GraphQL query:
Cannot query field "slug" on type "Mdx".
If you don't expect "slug" to exist on the type "Mdx" it is most likely a typo. However, if you expect "slug" to exist there are a
couple of solutions to common problems:
This happens because mdx.slug
has been removed from
v4 of the plugin.
Adding a slug field
If you’d like to keep using a slug
with MDX 2 and v4 of the plugin it’s necessary to create the slug
field yourself.
One way you can achieve this is using
onCreateNode,
createNodeField and the
createFilePath Helper Function
from gatsby-source-filesystem.
This approach relies on local file names broadly conforming to Semantic URLs / Clean URL guidelines.
For example:
|-- src
|-- pages
|-- ✅ this-is-fine.mdx
|-- ⚠️ this-/-could-/-be-/-problematic.mdx
In any case, if you’ve named your local .mdx
files sensibly you should be able to use them to form a slug
.
// gatsby-node.js
const { createFilePath } = require('gatsby-source-filesystem');
exports.onCreateNode = ({ node, getNode, actions: { createNodeField } }) => {
if (node.internal.type === 'Mdx') {
createNodeField({
node,
name: 'slug',
value: createFilePath({ node, getNode })
});
}
;
createPages
You can then use this new field in createPages
like this.
exports.createPages = async ({ graphql, actions: { createPage, createRedirect } }) => {
const {
data: { allMdx }
} = await graphql(`
query {
allMdx {
nodes {
id
+ fields {
+ slug
+ }
- slug
}
}
}
`);
allMdx.nodes.forEach((node) => {
const {
id,
+ fields: { slug },
- slug
} = node;
createPage({
path: slug,
...
});
});
};
File System Route API
And if you’re creating pages using collection routes you can use the new field like this.
|-- src
|-- pages
- {mdx.slug}.js
+ {mdx.fields__slug}.js
Querying fields.slug
In any GraphQL queries where you might have been using mdx.slug
, perhaps when creating a navigation using a
useStaticQuery hook, they will
now becomes the following.
// src/components/navigation.js
const {
allMdx: { nodes }
} = useStaticQuery(graphql`
{
allMdx {
nodes {
+ fields {
+ slug
+ }
- slug
frontmatter {
title
}
}
}
}
`);
It’s a small thing but having upgraded a few sites now I feel like this is the least manual way to work round the
missing mdx.slug
field.