How to Use Hygraph with Astro: Complete Guide
Step-by-step guide to integrating Hygraph with your Astro website.
Hygraph (formerly GraphCMS) is a GraphQL-native headless CMS that stands out for its content federation feature, which lets you combine data from multiple sources into a single GraphQL API. If you are already comfortable with GraphQL or you need to pull content from different backends into one unified schema, Hygraph is worth a serious look. With Astro, you can query Hygraph at build time and generate blazing-fast static pages from your CMS content.
Since Hygraph uses GraphQL as its primary interface, the integration relies on standard GraphQL queries rather than a proprietary SDK. This keeps things flexible and portable. Both the official Astro CMS guide and Hygraph's own documentation cover this pairing, so you are working with a well supported path.
Prerequisites
- Node.js 22.12.0 or later. Astro 6 dropped Node 18 and Node 20, so anything older will not run.
- An Astro project. Create one with
npm create astro@latest. This guide was checked against Astro 6.4.2. - A Hygraph account with a project created (free tier available, paid plans start at $199/mo)
- Basic familiarity with GraphQL queries
A Note on Rendering Mode
Astro renders everything as static HTML at build time by default, which is exactly what you want for a content site backed by a CMS. There is no output setting to flip on. The old output: 'hybrid' value was removed back in Astro 5, and static has been the default ever since.
The integration in this guide queries Hygraph at build time and emits static pages, so no adapter is required. If you later want a single route to fetch fresh Hygraph content on each request (for example a live preview page), you add an adapter and put export const prerender = false at the top of that one page. Everything else stays static. You only reach for an adapter when you actually need on-demand rendering.
Installation
Hygraph recommends graphql-request because it is lightweight, has good TypeScript support, and works in both Node.js and the browser. You do not need Apollo or anything heavy for build-time fetching:
npm add graphql-request graphql
This installs graphql-request 7.4.0 and its graphql peer dependency (16.14.0 at the time of writing).
Configuration
Create a reusable Hygraph client:
// src/lib/hygraph.ts
import { GraphQLClient } from "graphql-request";
const hygraph = new GraphQLClient(import.meta.env.ASTRO_HYGRAPH_ENDPOINT, {
headers: {
Authorization: `Bearer ${import.meta.env.HYGRAPH_TOKEN}`,
},
});
export default hygraph;
Add your Hygraph credentials to .env:
ASTRO_HYGRAPH_ENDPOINT=https://<region>.cdn.hygraph.com/content/<project-id>/master
HYGRAPH_TOKEN=your-permanent-auth-token
Hygraph's docs use the ASTRO_HYGRAPH_ENDPOINT name, and the endpoint follows the High Performance Content API shape shown above (your region and project id are baked into the URL). Find both values in your Hygraph project under Settings > API Access. Create a Permanent Auth Token with read access for your content stage.
Two things to keep in mind on Astro 6. First, only variables prefixed with PUBLIC_ are exposed to client-side code; the auth token here has no prefix, so it stays server-only and never ships to the browser, which is what you want. Second, Astro 6 always inlines import.meta.env values as-is and no longer coerces types, so a value like "true" stays a string. That does not affect this string endpoint, but it is worth knowing if you add boolean or numeric env vars elsewhere.
If your blog model is set to allow unauthenticated reads on the published stage, you can drop the Authorization header entirely. You must explicitly grant Content API permissions for that stage in your Hygraph project settings, otherwise queries return empty data with no error.
Set up your content model in Hygraph's dashboard. For a blog, create a "Post" model with fields: Title (Single line text), Slug (Single line text), Excerpt (Multi line text), Content (Rich text), Cover Image (Asset picker), and Published At (Date and time).
Basic Usage
Query posts from Hygraph and render them in Astro:
---
// src/pages/blog/index.astro
import hygraph from "../../lib/hygraph";
import { gql } from "graphql-request";
import BaseLayout from "../../layouts/BaseLayout.astro";
const { posts } = await hygraph.request(gql`
query Posts {
posts(orderBy: publishedAt_DESC) {
id
title
slug
excerpt
publishedAt
coverImage {
url
}
}
}
`);
---
<BaseLayout title="Blog">
<h1>Blog</h1>
{posts.map((post) => (
<article>
<a href={`/blog/${post.slug}`}>
{post.coverImage && (
<img src={post.coverImage.url} alt={post.title} loading="lazy" />
)}
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<time>{new Date(post.publishedAt).toLocaleDateString()}</time>
</a>
</article>
))}
</BaseLayout>
For individual post pages with dynamic routes:
---
// src/pages/blog/[slug].astro
import hygraph from "../../lib/hygraph";
import { gql } from "graphql-request";
import BaseLayout from "../../layouts/BaseLayout.astro";
export async function getStaticPaths() {
const { posts } = await hygraph.request(gql`
query PostSlugs {
posts {
slug
}
}
`);
return posts.map((post) => ({
params: { slug: post.slug },
}));
}
const { slug } = Astro.params;
const { post } = await hygraph.request(gql`
query Post($slug: String!) {
post(where: { slug: $slug }) {
title
content {
html
}
coverImage {
url
}
publishedAt
}
}
`, { slug });
---
<BaseLayout title={post.title}>
<article>
<h1>{post.title}</h1>
<time>{new Date(post.publishedAt).toLocaleDateString()}</time>
{post.coverImage && (
<img src={post.coverImage.url} alt={post.title} />
)}
<div set:html={post.content.html} />
</article>
</BaseLayout>
Production Tips
- Use Hygraph's image transformations, or Astro's image module. Append transformation parameters to asset URLs for automatic resizing and format conversion. For example, add
?width=800&height=400&fit=cropto any asset URL for on-the-fly optimization without a separate image service. If you would rather feed Hygraph assets through Astro's own<Image />component, add the asset host toimage.remotePatternsinastro.config.mjs:
// astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
image: {
remotePatterns: [{ protocol: "https", hostname: "**.graphassets.com" }],
},
});
Note that Astro 6 changed image defaults: cropping is now applied without an explicit fit option, and images are never upscaled by the default service.
Leverage content stages. Hygraph supports Draft and Published stages. Query the Draft stage for preview environments and Published for production. Use different auth tokens for each stage to keep things secure.
Set up webhooks for rebuilds. Under project settings, configure webhooks to trigger a rebuild on your hosting platform whenever content is published. This keeps your static site in sync without manual deploys.
Use content federation wisely. Hygraph's killer feature is federating external REST or GraphQL APIs into your schema. If you need product data from Shopify alongside blog content, you can query both through a single Hygraph endpoint.
Type your GraphQL responses. Generate TypeScript types from your Hygraph schema using GraphQL Code Generator (@graphql-codegen/cli, currently 7.1.0). This gives you autocomplete and compile-time safety for all your queries.
Alternatives to Consider
- Contentful if you want a REST API option alongside GraphQL and a larger ecosystem of integrations.
- Sanity if you need real-time collaboration features and a more flexible schema builder with GROQ queries.
- DatoCMS if you prefer a similar GraphQL-first CMS with built-in image optimization and a simpler pricing model.
Common Errors and Fixes
Queries return empty data and no error. This almost always means the content stage is not readable by your request. Hygraph requires you to explicitly initialize Content API permissions for unauthenticated requests, or to query with a Permanent Auth Token that has read access to the stage you are targeting. Check Settings > API Access and confirm the published stage is allowed for the role your request uses.
Images do not optimize or throw a remote-image error. Astro will refuse to process a remote image whose host is not allowlisted. Add **.graphassets.com to image.remotePatterns in astro.config.mjs as shown above. If you only ever use raw asset URLs with Hygraph transformation query parameters, you can skip Astro's image module entirely.
New posts do not show up after publishing in Hygraph. Astro builds every route at build time, so getStaticPaths is evaluated once during the build and not on each request. Fresh content only appears after a rebuild. Wire a Hygraph webhook to your host's deploy hook so publishing triggers a new build, or move a single preview route to on-demand rendering with export const prerender = false plus an adapter.
import.meta.env.ASTRO_HYGRAPH_ENDPOINT is undefined. Confirm the variable name matches exactly, including the ASTRO_ prefix, and that the .env file sits at the project root. Restart the dev server after editing .env since Astro reads it at startup. Remember that on Astro 6 only PUBLIC_-prefixed variables are available in client-side code; build-time frontmatter access works for any name.
Build fails right after upgrading. Astro 6 requires Node 22.12.0 or later. If your CI or local runtime is on Node 18 or 20, the build will not run. Bump your runtime first.
Official Docs and Examples
- Astro CMS guide for Hygraph: https://docs.astro.build/en/guides/cms/hygraph/
- Hygraph official Astro implementation guide: https://hygraph.com/docs/implementations/astro/astro
- Hygraph Astro starters (microblog, e-commerce): https://hygraph.com/docs/implementations/astro/starters
- Working example project (
with-astro) in Hygraph's examples repo: https://github.com/hygraph/hygraph-examples/tree/master/with-astro - Astro on-demand rendering reference (for the preview-route case): https://docs.astro.build/en/guides/on-demand-rendering/
Wrapping Up
Hygraph and Astro work well together for content-driven sites, especially when you need GraphQL flexibility or content federation. The free tier covers small projects, and the GraphQL API means you query exactly the data you need with no over-fetching. If your project involves pulling content from multiple sources or you prefer GraphQL over REST, Hygraph is a solid foundation for your Astro site.
Sources
All versions and facts below were checked on 2026-05-29.
- Astro CMS guide: Hygraph & Astro
- Hygraph docs: Astro + Hygraph implementation
- Hygraph docs: Astro starters
- Hygraph examples repo (with-astro)
- Astro docs: On-demand rendering
- Astro docs: Upgrade to v6 (Node 22.12.0 minimum, env var inlining, image defaults)
- Astro 5.0 release notes (output: 'hybrid' removed, static is default)
- npm: graphql-request 7.4.0
- npm: graphql 16.14.0
- npm: astro 6.4.2
- npm: @graphql-codegen/cli 7.1.0
Related Articles
How to Use Algolia with Astro: Complete Guide
Step-by-step guide to integrating Algolia with your Astro website.
How to Integrate Auth0 with Astro: Complete Guide
Step-by-step guide to integrating Auth0 with your Astro website. Setup, configuration, and best practices.
How to Use AWS Amplify with Astro: Complete Guide
Step-by-step guide to integrating AWS Amplify with your Astro website.