How to Configure a Path Alias in a React Typescript App for cleaner imports
Table of Contents
Introduction
As your Typescript React project grows with everything neatly separated in their own folder, the importing processes starts to become messy. This is specially true if we are following a project structure like react-bulletproof.
Problem
Your project strucure may look like this:

and for us to import Button.tsx
in TodoItem.tsx
, our import statement will look something like this:
import React from 'react'; import { Button } from '../../../components/elements/Button'; export const TodoItem = () => { return <div></div>; };
our issue here is that we are doing way too many ../../../
statements in the path, and this can get longer if we are importing from a deeper sturcture level. This is specially frustrating as we won’t always import from the same level, causing us to try to figure out where we are to reach that other path. It’s true that intellisense in VS Code will let us know at which folder we are as we are importing, but there is a better approach to this.
Solution
Setting a Path Alias will help us have a more definite and clearer way to import in react:
import React from 'react'; import { Button } from '@/components/elements/Button'; export const TodoItem = () => { return <div></div>; };
The beauty of this is that regardless of at which depth level we are at, the import statement will always be the same.
What is a Path Alias?
A path alias in typescript allows us to define a word or a path to represent an absolute path in the project.
so, in our case, we want to represent ./src
with the alias @/
.
Configuring an Alias
to configure an alias, we firstly need a new file at our project’s root (not inside ./src
).
we will call it tsconfig.paths.json
, and add the following configuration to it:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": [ "./src/*" ] } } }
to be able to use this configuation in our project, we will extend it in our tsconfig.json
file, which is also located at our project’s root.
{ "compilerOptions": { "target": "es5", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": [ "src" ], "extends": "./tsconfig.paths.json" // 👈 add this line }
Why are we not putting this configuation in tsconfig.json right away instead?
this is because on startup, react (and later, craco) cleans up tsconfig.json
to only keep the configuration that it expects to be there for it to work properly. paths
property is one of those that it removes when it starts up.
creating tsconfig.paths.json
and extending it in tsconfig.json
will help us work around that issue.
Testing the Path Alias
You can immediately notice that intellisense will resolve the path alias we defined, and our imports seemingly work.

However, the moment we use the component,
import React from 'react'; import { Button } from '@/components/elements/Button'; export const TodoItem = () => { return ( <div> <Button onClick={() => {}} label='Click Me' /> </div> ); };
this error will come up:

so what is going on here?
We need to do an additional configuration for CRA (Create React App).
Using Storybook? then you very likely will face a similar issue to this one, and you can find the solution in “How to resolve a path alias in Storybook”
Resolving the Alias in CRA (Create React App)
Under the hood, CRA is using webpack. Among many other things, it is using it to resolve imports.
What we need to do is to modify that webpack configuration for it to resolve the alias we just defined in our tsconfig.json.
There are multiple ways to achieve that, but the most convenient way, and the way I recommend will be CRACO.
CRACO
CRACO is a package that helps us override CRA’s configurations without the need to eject.
Install CRACO
yarn add @craco/craco
Override the Webpack Configuration
Create craco.config.js
at your project’s root. (not inside src/
)

and put in the following configuration:
const path = require('path'); module.exports = { webpack: { alias: { '@': path.resolve(__dirname, 'src'), }, }, };
Change the react scripts to CRACO
in package.json
, change from react-scripts to craco to each of start
, build
, test
and eject
.
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" }
this means that we will need to restart our react app if it was already running, as we won’t be using react-scripts to start it up anymore.
Start React App with CRACO’s start script
It’ll be just like how we always started our react app.
yarn start
and this time, our react app will not be throwing any errors for not being able to resolve our path alias!
Conclusion
Path aliases are a very good way to have more consistent import statements across our typescript projects. We can have more
Thanks, this helped me 😉
I’m glad that it helped!
Thanks this helped to identify the issue. However, I did not use that , and used absolute typescript imports to leave it at the moment.(https://create-react-app.dev/docs/importing-a-component/#absolute-imports)
That’s actually a nice solution to the problem! Simpler to implement too.
Thanks, it worked!
Welcome!
I spent a whole day trying to solve the CRA issue, nothing pointed to the right direction until I found your post.
Really thanks
I’m so glad that it helped you out!
Thank you! This was really helpful!
welcome!