During my React based development, I'll find myself importing a module from '../../../components/Widget' and that ../../../ is anyone's guess if it's right first time or not.

Except I discovered that Next.js (which is what I do most of my React dev with) ships with a trick up its sleeve.

UK EVENTAttend ffconf.org 2024

The conference for people who are passionate about the web. 8 amazing speakers with real human interaction and content you can't just read in a blog post or watch on a tiktok!

Update 2020-12-19 - the latest Next.js supports aliases directly through jsconfig.json, so you can skip straight to that part and you get path aliases for (nearly) free!


Next.js uses a preconfigured webpack under the hood that you don't need to mess with.

There's a helpful webpack plugin that let's you alias paths, so I could alias ~ to the root of my project, letting my imports look like this:

import Widget from '~/components/Widget'

Much cleaner. Knowing which plugin this is and how to configure it will be time and energy wasted. Which is why it was nice to find that Next.js silently shipped with it by default.

In the wild

If you're familiar with Next.js already, you might have used the alias already without knowing.

import Head from `next/head`

The above code is actually using the alias feature. Under the hood Next is aliasing a number of their modules to the distribution builds:

alias: {
  // These aliases make sure the wrapper module is not included in the bundles
  // Which makes bundles slightly smaller, but also skips parsing a module that we know will result in this alias
  'next/head': 'next/dist/next-server/lib/head.js',
  'next/router': 'next/dist/client/router.js',
  'next/config': 'next/dist/next-server/lib/runtime-config.js',
  'next/dynamic': 'next/dist/next-server/lib/dynamic.js',

This means it's (relatively) straight forward to add our own custom alias path.

Customising the alias

Add the next.config.js file to your project then it needs to add to the webpack.config.resolve.alias object:

const path = require('path');

module.exports = {
  webpack: config => {
    config.resolve.alias['~'] = path.resolve(__dirname);
    return config;

That's it. Now I can import from '~/components/Widget' and all is well.

Bonus: VS Code support

I'm a VS Code user (so if you're using another editor, please comment below to share how this is done). This means I can alt+click on imported packages and the source will be loaded.

VS Code needs to understand where how I've configured my alias. This is matter of adding a jsconfig.json file to my project's root:

  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "~/*": ["./*"]

Now everything works and I don't have to type so many period characters 🎉