Logo with initials

Migrating to Gatsby ESM

Since v5.3, you can use ES modules in Gatsby. I’m glad this is finally out because there’s no reason to use CommonJS today.

I recently migrated this website, and there were a few road blocks along the way. Here’s a quick migration guide to help you out. There’s also the official release notes.

1. Rename files

Node treats files with the .mjs extension as ES Modules.

  1. gatsby-config.js -> gatsby-config.mjs
  2. gatsby-node.js -> gatsby-node.mjs
  3. 🙋‍♂️ gatsby-ssr.js stays the same, be careful with that one.

2. Fix reliance on __dirname in your config

I used __dirname in my gatsby-config.mjs, like this:

  resolve: `gatsby-source-filesystem`,
  options: {
    path: `${__dirname}/content/`, // doesn't work
    // ignore drafts
    ignore: [`${__dirname}/content/drafts/**`], // doesn't work

In ESM, the global __dirname doesn’t exist anymore, you can patch this with the following code:

// add this to the top of your config file
import { fileURLToPath } from 'url';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
// Taken from Aral Balkan: https://ar.al/2021/01/27/commonjs-to-esm-in-node.js/#__dirname

3. Local plugins

  resolve: require.resolve('./plugins/gatsby-remark-inline-svg'),


  resolve: './plugins/gatsby-remark-inline-svg',

You don’t have to, but I’d encourage you to convert your local plugins to ESM too.

4. In your files

If you’re importing other local files in gatsby-node.mjs, make sure:

  1. You’re not mixing require and import in those files
  2. Those files are .mjs too
import { resolve } from 'node:path';
import { createFilePath } from 'gatsby-source-filesystem';

- import createSocialCard from './src/utils/create-social-card.js';
+ import createSocialCard from './src/utils/create-social-card.mjs';