Gatsby is a React-based static site generator with a powerful GraphQL data layer that can pull content from CMSs, Markdown, APIs, and more at build time. The payoff is a fast, pre-rendered site; the cost is a heavier build than simpler SSGs. Here's how to deploy one to production cleanly.
The Gatsby build pipeline
Gatsby's build does a lot: it runs source plugins to populate the GraphQL data layer, renders every page to HTML, and produces an optimized bundle. The command is simply:
gatsby buildThe output lands in the public/ directory — a complete static site. (Note: this is different from gatsby serve, which only previews an already-built site locally.)
Builds can be slow — use the cache
Gatsby builds are the heaviest part of the workflow, especially for large sites. The .cache and public directories hold incremental build data. When supported, preserving these between builds dramatically speeds up rebuilds via Gatsby's incremental builds.
Don't commit .cache to Git, but do let your CI/platform cache it between runs if it offers that. For a first deploy expect a full build; subsequent ones can be much faster.
Environment variables: build-time vs runtime
This trips up nearly everyone. Because Gatsby pre-renders at build time, only variables prefixed with GATSBY_ are available in the browser bundle, and they're inlined at build time:
// Available in client-side code:
const apiUrl = process.env.GATSBY_API_URL;Server-only secrets (CMS API keys used by source plugins) are read during gatsby build and should not be prefixed with GATSBY_, so they stay out of the client bundle:
// gatsby-config.js — runs at build time, server-side
require('dotenv').config();
module.exports = {
plugins: [
{
resolve: 'gatsby-source-contentful',
options: { accessToken: process.env.CONTENTFUL_TOKEN },
},
],
};Set both kinds in your platform's environment configuration so the build has what it needs.
Set the site URL
Many SEO plugins (sitemap, RSS, canonical) need your production URL. Configure siteMetadata.siteUrl:
module.exports = {
siteMetadata: {
siteUrl: 'https://example.com',
title: 'My Gatsby Site',
},
};Image and asset optimization
Gatsby's gatsby-plugin-image produces responsive, lazy-loaded, modern-format images at build time. It's one of Gatsby's biggest strengths — use it instead of raw tags for any meaningful imagery.
Deploying on PandaStack
- 1Connect your Git repository as a static site.
- 2PandaStack auto-detects Gatsby and runs
gatsby build. - 3Set your
GATSBY_*public vars and any server-side CMS tokens in the dashboard. - 4Add your custom domain — automatic SSL is issued.
- 5Push — it rebuilds and redeploys with live build logs.
Builds run in fast microVMs. The free tier includes 5 static sites with 100 GB/month bandwidth and 300 build minutes (Pro raises this to 1000 build minutes and unlimited static), which matters for Gatsby's heavier builds.
| Setting | Value |
|---|---|
| Build command | gatsby build |
| Output dir | public |
| Public vars | GATSBY_* prefix |
| Server vars | no prefix (build-time only) |
| TLS | Automatic SSL |
Common pitfalls
- Expecting non-
GATSBY_vars in the browser — they won't be there; onlyGATSBY_*are inlined. - Leaking a CMS token — never prefix a secret with
GATSBY_. - Wrong output dir — Gatsby outputs to
public. - Underestimating build minutes — large Gatsby sites build slowly; budget accordingly.
- Missing
siteUrl— breaks sitemap and canonical metadata.
References
- Gatsby deployment overview: https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/
- Gatsby environment variables: https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/
- Gatsby incremental builds: https://www.gatsbyjs.com/docs/reference/release-notes/v2.20/
- gatsby-plugin-image: https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image/
- Gatsby build process: https://www.gatsbyjs.com/docs/conceptual/overview-of-the-gatsby-build-process/
---
PandaStack serves your Gatsby build from the edge with automatic SSL, and the free tier's build minutes handle real-world Gatsby sites. Connect your repo and push: https://dashboard.pandastack.io