Gatsby supports TypeScript out-the-box. Unfortunately, the official solution has several shortcomings which limit its usefulness. There is a better way.

Rather than using Babel to compile our TypeScript, we can run Gatsby on ts-node. That gives us proper type-checking, along with TypeScript support in Gatsby's configuration files.

Install your dependencies

Install your dependencies as follows. Be sure to specify the correct Node version (version 12 in the example).

$ yarn add typescript ts-node
$ yarn add --dev @types/node@12 @types/react @types/react-dom

Configure the TypeScript compiler

Create a tsconfig.json file in the root of your project, with the following contents.

{
  "include": ["./src/**/*"],
  "compilerOptions": {
    "target": "es2019",
    "module": "commonjs",
    "lib": ["dom", "es2020"],
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "resolveJsonModule": true
  }
}

Update Gatsby Config

Gatsby requires a gatsby-config.js file in the project root. We use this file to register ts-node as the loader for all future require statements.

// ./gatsby-config.js
require('ts-node').register({ files: true, transpileOnly: true })

module.exports = require('./gatsby-config.ts')

With that in place, move your site configuration to gatsby-config.ts.

// ./gatsby-config.ts
export const siteMetadata = {
  title: 'My Site',
  siteUrl: 'https://www.mysite.com',
}

export const plugins = [
  {
    resolve: 'gatsby-source-filesystem',
    options: { name: 'images', path: `${__dirname}/src/images` },
  },
]

Update Gatsby Node

Gatsby also requires a gatsby-node.js file in the project root. Move the bulk of your code to separate TypeScript files, and load them as needed.

// ./gatsby-node.js
const { createPages } = require('./lib/bootup/createPages')

/** @type { import("gatsby").GatsbyNode } */
const config = {}
exports.config = config

config.createPages = createPages

module.exports = config

Here’s how a bare-bones createPages.ts file might look.

// ./lib/bootup/createPages.ts
import { GatsbyNode } from 'gatsby'

export const createPages: GatsbyNode['createPages'] = async ({
  graphql,
  actions: { createPage },
}) => {
  // Create your pages
}

Get back to work

These are all the changes you need to use TypeScript—and type-checking—with Gatsby.