
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI understand your predicament! You're trying to fetch Sanity content at runtime in Gatsby rather than at build time, while maintaining clean URLs like /category/the-article-slug. This is definitely possible, though it does go against Gatsby's typical static generation approach.
The Stack Overflow response saying it's impossible is incorrect. Gatsby has a matchPath feature specifically for client-only routes that will solve your problem.
When you create your page in gatsby-node.js, specify a matchPath that matches your dynamic URL pattern:
// gatsby-node.js
exports.createPages = async ({ actions }) => {
const { createPage } = actions
createPage({
path: '/article', // The actual page component path
matchPath: '/:category/:slug', // This matches your URL pattern
component: require.resolve('./src/templates/article.js'),
})
}In your article.js template, access the route parameters and fetch from Sanity at runtime:
// src/templates/article.js
import React, { useEffect, useState } from 'react'
import sanityClient from '@sanity/client'
const client = sanityClient({
projectId: 'your-project-id',
dataset: 'production',
useCdn: false, // Use false for fresh data
apiVersion: '2023-01-01'
})
const ArticlePage = ({ location }) => {
const [content, setContent] = useState(null)
useEffect(() => {
// Extract category and slug from the URL
const pathParts = location.pathname.split('/').filter(Boolean)
const [category, slug] = pathParts
// Fetch from Sanity at load time
const query = `*[_type == "article" && category->slug.current == $category && slug.current == $slug][0]`
client.fetch(query, { category, slug })
.then(data => setContent(data))
.catch(err => console.error(err))
}, [location.pathname])
if (!content) return <div>Loading...</div>
return (
<article>
<h1>{content.title}</h1>
{/* render your content */}
</article>
)
}
export default ArticlePageThe matchPath parameter tells Gatsby: "When someone visits any URL matching /:category/:slug, serve the article.js component and let it handle the routing client-side." This is exactly what you need - clean URLs with runtime content fetching.
SEO Impact: Since content loads at runtime on the client, search engines won't see the content in the initial HTML. This is a significant SEO disadvantage compared to static generation.
Performance: You'll lose the performance benefits of pre-rendered pages, as each visit requires a client-side API call to Sanity.
Alternative Approaches (if you have any flexibility):
The matchPath approach will work perfectly for your /category/the-article-slug URL structure while fetching content at load time. This is a documented Gatsby feature designed exactly for client-only routes and SPA-like behavior within Gatsby sites.
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store