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.

[I’ve published 38 videos for new developers, designers, UX, UI, product owners and anyone who needs to conquer the command line today.](https://training.leftlogic.com/buy/terminal/cli2?coupon=BLOG\&utm_source=blog\&utm_medium=banner\&utm_campaign=remysharp-discount)

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

Alias[](#alias)

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[](#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](https://github.com/zeit/next.js/blob/f632567bcf6652333ab57e7c13adeabe15bf1074/packages/next/build/webpack-config.ts#L159) 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[](#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[](#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 🎉

Comments

Lock Thread

Login

Add Comment[M ↓   Markdown]()

[Upvotes]()[Newest]()[Oldest]()

0 points

3 years ago

Hi there, this is now part of Next.js: https://github.com/zeit/next.js/pull/11293

All you need is a jsconfig.json file and it will handle the aliases while also configuring your editor to autocomplete them if it supports jsconfig.json.

Thanks for the article!

Nguyễn Lê Quang Anh

0 points

3 years ago

https://i.imgur.com/S6tafBx.png I got this error, can you help me?

0 points

4 years ago

For some reason this only works when using the ".js" file extension…​ As soon as I try to use ".jsx", ".ts" or ".tsx" it just throws "Cannot find module '\~/components/DefaultLayout'".

EDIT: I figured it out. When using TypeScript I also need to configure "compilerOptions.paths" in tsconfig.json.

![](/images/no-user.svg)

Tomer Almog

0 points

4 years ago

in webstorm you need to add a file (I named mine webstrom-config.js) on the root with this code:

System.config({ "paths": { "\~/": "./" } });

0 points

4 years ago

Thanks for this. Although you don’t need the line:

const webpack = require('webpack');

1 point

4 years ago

You’re right.

Christopher Esplin

1 point

4 years ago

I like this pattern. Thanks for saving me a bunch of time!

0 points

4 years ago

Or you could simply do config.resolve.modules = [__dirname, 'node_modules']; (or of course resolve to the src directory, like in the [webpack docs example](https://webpack.js.org/configuration/resolve/#resolvemodules)).

That way, you don’t even have to use tilde and only need to specify baseUrl in that jsconfig.json. (Or of course if you use TS - the same in tsconfig.json.)

0 points

4 years ago

I’m working on a project that didn’t use ~ in the code, and it was extremely confusing to me as to what was an installed dep and what was local.

0 points

4 years ago

This is a great pattern. I was previously aliasing each individual root folder, as needed. Using ~ is much simpler.

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.

This is a default feature in Webpack https://webpack.js.org/configuration/resolve/#resolvealias, which is what you’re using in your next.config.js example. So you are, in fact, editing a webpack configuration :)

Andrew Rabon

0 points

4 years ago

Hm, the leading tilde seems to complicate things. If you’re not married to it, the jsconfig.json method should be enough to import e.g. 'component/MyComponent' anywhere in the tree.

A version I’ve been using is:

{ "compilerOptions": { "baseUrl": "./src" }}

Not sure how much this applies to Next.js-flavored React though. 😬

1 point

4 years ago

So, this post is really about the build being able to use aliases. With the jsconfig.json file alone, the editor is able to do the work, but when I run npx next it can’t resolve the ~/components/… path at all. Which is why I need to add the next.config.js change. But that’s all I need - I didn’t configure webpack plugins or anything else.

Andrew Rabon

0 points

4 years ago

Ah gotcha, that’s still pretty cool then! The less mucking with Webpack the better (though things seem to be better these days.)

[Commento](https://commento.io)