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.
[](https://training.leftlogic.com/buy/terminal/cli2?coupon=BLOG\&utm_source=blog\&utm_medium=banner\&utm_campaign=remysharp-discount)
[READER DISCOUNTSave $50 on terminal.training](https://training.leftlogic.com/buy/terminal/cli2?coupon=BLOG\&utm_source=blog\&utm_medium=banner\&utm_campaign=remysharp-discount)
[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)
[$49 - only from this link](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 🎉
Published 4-Nov 2019 under #code. [Edit this post](https://github.com/remy/remysharp.com/blob/main/public/blog/nice-imports-with-nextjs.md)
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.

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)