Getting Started With TypeScript in Gatsby

Lennart Jörgens
Lennart Jörgens
March 30th, 2022

TypeScript continues to rise in popularity and satisfaction among developers as it gives them among other things type-safety for their code and better IDE completion. While Gatsby has support for writing pages with TypeScript for two years already, one of the top feature requests was the ability to author gatsby-config and gatsby-node with TypeScript instead of CommonJS. Since GatsbyConf 2022 this feature request is implemented now! And as a sneak-peak into the future: We’ll be working on better integration of automatically generating TypeScript types from your GraphQL queries.

If you want to learn all about Gatsby in TypeScript, go check out our How-To Guide on TypeScript in Gatsby. In this post you’ll learn how you can leverage these new capabilities when starting a new Gatsby project and how I like to set up a new project from scratch. You can find the code for this post on GitHub.

Initializing the project

The easiest way to start a new project is via the CLI. Make sure that you set up your development environment to be able to use the following commands.

Go to a directory of your choice and type the following into your terminal:

In the following prompts, choose TypeScript as your preferred language and choose vanilla-extract as your styling solution. If you’ve never heard of vanilla-extract before (as a CSS styling solution 😉), you can think of it as “CSS modules in TypeScript” which enables you to write type-safe CSS that gets build to static CSS. Here’s how your questionnaire should look like:

Go to the newly created project (with cd getting-started-with-type-script-in-gatsby) and open it in your favourite editor (e.g. with code .). You can start the project with npm run develop , navigate to http://localhost:8000 in your web browser, and see yourself greeted with a message: “Congratulations — you just made a Gatsby site! 🎉🎉🎉”. You can stop the development server for now as you’ll be writing some code in gatsby-node.ts which requires a restart of the server.

gatsby-config.ts

The set up process already created a gatsby-config.ts for you. You can use it like you’re used to with gatsby-config.js with the difference that the syntax changed from CommonJS to ES6. The config in your project should look like this:

So you can use the GatsbyConfig type on the exported config object in your projects. Try it out on the config object, you should get autocompletion for other keys like pathPrefix or trailingSlash. Please note that you won’t get autocompletion for the items inside the plugins array.

gatsby-node.ts

I’m personally super excited about the ability to write gatsby-node in TypeScript. If you’ve never used this file before: This is where you can access and use all of Gatsby’s public APIs. In this post you’ll create Person nodes that represent a small slice of all the awesome women in STEM. You can use the GatsbyNode TypeScript type for all public APIs, in this case you’ll use sourceNodes . Once you add the type you’ll get autocompletion for the function arguments and nested options. Try it out yourself by writing the following:

Awesome to finally get IDE help, right? While not mandatory, I personally like to write type imports with import type to make it more explicit. Bundlers also can use this information for better tree-shaking. You should extend the gatsby-node.ts file to the following to have a working example:

You’ve successfully created Person nodes. With the above example you’ll have experienced that the createNode function of course is also typed and hints you that id and internal are mandatory. Other than the GatsbyNode type not much is different between the CommonJS and TypeScript variant of gatsby-node.

Pages and PageProps

Now it’s time to query and display a list of persons that you just created. For type-safety in your pages (that is any files inside src/pages/*) you’ll want to use the PageProps type. This type takes in a couple of generics, most importantly as the first argument the DataType which will be the shape of the response from the GraphQL query.

Start by removing the contents of src/pages/index.tsx and replace it with the following:

So you add PageProps to the arguments of the function. Go to the typed object and try auto-completion. You’ll get suggestions for values that are typical for a Gatsby page like pageContext, data, and more.

Restart the development server with npm run develop and go to http://localhost:8000. You should see your “Hello World”. In a new tab, go to http://localhost:8000/___graphql to have the GraphiQL user interface open. You can use the “Explorer” sidebar on the left (if not already open, press the “Explorer” button at the top) to construct the following query:

Execute the query and you should get back the persons you’ve defined earlier. Place this query now inside the src/pages/index.tsx. You can use the “Code Exporter” button in GraphiQL to help you write that boilerplate code. Also write out the DataType type for better type-hinting of your page query.

Here’s how your index page should look like:

As you can see the newly defined DataType type is used in PageProps as a generic. This has the result that data is typed with the given information. Now, create an unordered list below the h1 heading with the data you’re given. It’ll look like this:

Congrats, you’ve successfully used gatsby-config.ts, gatsby-node.ts in a Gatsby project and created nodes of a custom Person type that you displayed as a list. Through all that you ensured type-safety by strongly typing your functions and return types. With these things in mind you should be well prepared to write the rest of your Gatsby project in TypeScript. And if you need any further information, go check out the How-To Guide on TypeScript in Gatsby as it goes more into details for things like:

  • What the other generics of PageProps are
  • Types for gatsby-browser.tsx and gatsby-ssr.tsx
  • How to type getServerData
  • And what limitations you might run into when using TypeScript in gatsby-config.ts and gatsby-node.ts

Also, one more thing: Keep reading to learn how I currently like to style React & TypeScript projects and you’ll be in for a treat 🧁.

Styling

This last section will be all about styling. It’s not specific to Gatsby and its latest TypeScript features, however we recently updated our documentation to recommend vanilla-extract as a styling solution — so I want to give you a quick introduction in how it works in this example project.

As you’ve chosen vanilla-extract as a styling option in the beginning (in the npm init gatsby step) everything is already set up for you. Anything related to vanilla-extract needs to be written in .css.ts files so that the build tool (in Gatsby’s case that is webpack at the time of writing) can compile these down to CSS files.

Start by creating a new folder inside src called styles and create the file index.css.ts. You’ll write the styles for the index page here:

The style functions take an object as an argument containing valid CSS keys. You get full type-safety and autocompletion for your CSS through that — how awesome is that?! The list and listItem need to be named exports so that you can use it in your React code. The globalStyle definition gets evaluated as the two other styles will be pulled into the bundle. You could also put all global styles into a separate file (see vanilla-extract example) but then you’ll need to make sure to import it in your code at least once.

Now you’ll see why the “CSS Modules in TypeScript” description kinda makes sense. In normal CSS modules you write your classes (e.g. .list {}) and then these classes are available as named exports from the file. The same syntax happens with vanilla-extract.

Here’s how your page should look like after applying styles:

Both the list and listItem are imported from the index.css.ts file and then used inside className. Go to your live preview of the site at http://localhost:8000 and see your changes applied. When you inspect the HTML, you’ll see that the ul and li now have class names attached to them, e.g. styles_listItem__10u4iz31. During gatsby develop the class name also contains the style names (for debugging purposes), in the production build it’ll just be a hash. So exactly like CSS modules you get scoped CSS!

Where to go from here

And that’s it for this small example. There’s certainly a lot more to learn but the basics should enable you to migrate an existing project to TypeScript or starting a new one from scratch. As said previously, the How-To Guide on TypeScript in Gatsby is the source of truth for all things TypeScript in Gatsby. You can check out the vanilla-extract example to learn more about vanilla-extract or the using-typescript example for other type usages.

Last but not least, you can also check out gatsby-starter-tmdb (live at tmdb.lekoarts.de) which I created in TypeScript with vanilla-extract. This is a real-world example of this stack and should give you even better guidance on how to use things.

Lennart Jörgens

Software Engineer at Netlify• he/him • Passionate about working on open source & making the web more inclusive

Follow Lennart Jörgens on Twitter

Talk to our team of Gatsby Experts to supercharge your website performance.