next.js icon indicating copy to clipboard operation
next.js copied to clipboard

Next.js 15 import alias not working with turbopack

Open aelassas opened this issue 1 year ago • 4 comments

Link to the code that reproduces this issue

https://github.com/aelassas/next-turbopack

To Reproduce

Create a Next.js 15 project with an internal package package1:

| - my-app/
| - packages/package1/

Add the alias in tsconfig.json:

{
  "compilerOptions": {
   ...
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"],
      ":package1": ["../packages/package1"],
    },
  }
}

Import :package1 in a page or component:

import * as package1 from ':package1'
...

Run the dev server with turbopack.

Current vs. Expected behavior

When I run the dev server without turbopack, it works fine. But when I try with turbopack I always get this error:

Module not found: Can't resolve ':package1'
Import map: aliased to relative "../packages/package1" inside of [project]/

Provide environment information

Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32593
  Available CPU cores: 12
Binaries:
  Node: 20.17.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.0.2-canary.7 // Latest available version is detected (15.0.2-canary.7).
  eslint-config-next: N/A
  react: 19.0.0-rc-1631855f-20241023
  react-dom: 19.0.0-rc-1631855f-20241023
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Turbopack

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

No response

aelassas avatar Oct 26 '24 03:10 aelassas

I got this issue when I used a alias outside of the baseUrl. Had to restructure and use the experimental.turbo.resolveAlias in my next.config.ts to use that external package. I think if you added ":package1": "../packages/package1" there it should work. You might have to mess with the aliased path a bit to get it working.

dualdetail avatar Oct 26 '24 17:10 dualdetail

@dualdetail I have tried with the following config before submiting this issue but got the same error:

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    turbo: {
      resolveAlias: {
        ':package1': '../packages/package1',
      },
    },
  },
}

export default nextConfig

I think it should work with tsconfig.json without having to tweak turbo config.

aelassas avatar Oct 26 '24 17:10 aelassas

@dualdetail After playing with turbo config, I found a workaround:

const nextConfig = {
  experimental: {
    turbo: {
      root: '..',
      resolveAlias: {
        ':package1': '../packages/package1',
        ':package2': '../packages/package2',
      },
    },
  },
};
export default nextConfig;

Setting root to .. fixed the issue. But as I said in my previous comment, it should work with tsconfig.json without having to tweak turbo config.

Anyway, thanks for your hint.

aelassas avatar Oct 26 '24 21:10 aelassas

Yeah it's just a workaround. Glad you got something working in the meantime

dualdetail avatar Oct 27 '24 01:10 dualdetail

Turbopack has stricter filesystem access than webpack by default to ensure that files outside of the project directory are not leaking into the compilation which causes the caches to be invalidated too often (i.e. when you deploy a part of the work would always have to be repeated).

We automatically detect the root by looking for a lockfile, in case of your reproduction there is no lockfile so it uses the default of the original project directory. Relevant code: https://github.com/vercel/next.js/blob/1ce3913ef13a22c03d795df7cc8eec2cf0a7ee37/packages/next/src/lib/find-root.ts#L6

We should add a clearer error for these resolving failures to highlight the reason it can't resolve is the path going out of the project root.

timneutkens avatar Oct 29 '24 10:10 timneutkens

We automatically detect the root by looking for a lockfile, in case of your reproduction there is no lockfile so it uses the default of the original project directory. Relevant code:

https://github.com/vercel/next.js/blob/1ce3913ef13a22c03d795df7cc8eec2cf0a7ee37/packages/next/src/lib/find-root.ts#L6

We should add a clearer error for these resolving failures to highlight the reason it can't resolve is the path going out of the project root.

In my case, I started with a single project and later migrated to workspaces. Turns out I still had a bun.lockb in the directory of a module, so Turbopack thought that's where the project started, even though there was another bun.lockb in the parent directory.

Deleting the ./apps/frontend/bun.lockb fix it for me, didn't even need the resolveAlias. Thanks!

TechnologicNick avatar Dec 03 '24 00:12 TechnologicNick

I also have Same issue when i using turbopack but i have more Alias so i directly imported from tsconfig.json also i havve imageloader issue on turbopack

// next.config.ts
import { jsonc } from 'jsonc';

let tsconfig: any = jsonc.parse(fs.readFileSync(path.resolve(__dirname, 'tsconfig.json'), 'utf-8'));

...

const nextConfig: NextConfig = {
...
    experimental: {
        turbo: {
            resolveAlias: {
                ...Object.fromEntries(
                    Object.entries(tsconfig.compilerOptions.paths).map(([key, value]: any) => [
                        key.replace('/*', ''),
                        path.resolve(path.resolve(), value[0].replace('/*', ''))
                    ])
                )
            },
            // ! Turbo Pack Missing Loader
            // rules: {
            //     // ? Image Loader
            //     'image/*': {
            //         loader: 'remote',
            //         asset: "sdfsd",
            //     },
            // }
        }
    },
...
}

MeetBhingradiya avatar Mar 29 '25 13:03 MeetBhingradiya

From the point of view of a working webpack configuration, this turbopack behaviour represents a regression. Willing to accept that our webpack approach is wrong, but it seems incorrect to have to maintain two contradicting configs for the two sets of tooling.

In our monorepo, modules within the repository are resolved directly to their typescript source in the module's src/index.ts with no build step. In most tooling this is simply the --condition flag, or a customCondition config but we found explicit aliasing to absolute module path to work for next webpack.

However, attempting the same within the dev task with turbo enabled results in errors logged like...

https://nextjs.org/docs/messages/module-not-found
[...]
Import map: aliased to server relative '/Users/user/workspace/monorepo-root/modules/my-module/src' inside of [project]/servers/my-server

I think server relative means it settles to ./Users/user/workspace/monorepo-root/modules/my-module/src which is surely a contradiction that makes it impossible to migrate to turbopack tooling given an absolute path seemed to be needed by webpack.

Here's our (anonymised) source which works fine for webpack and chokes on turbopack.

const REPO_SCOPE = "@my-scope";

const repoModules = Object.keys({
  ...dependencies,
  ...devDependencies,
}).filter((packageName) => packageName.startsWith(REPO_SCOPE));

const repoAlias = Object.fromEntries(
  repoModules.map((moduleName) => {
    const shortName = moduleName.replace(`${REPO_SCOPE}/`, ""); // remove scope
    const modulePath = path.resolve(`../../modules/${shortName}/src`); // derive path
    return [moduleName, modulePath];
  }),
);

/** EXPORT RESULTING CONFIG */

export default {
  webpack: (config, _options) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      ...repoAlias,
    };
    return config;
  },
  experimental: {
    turbo: {
      resolveAlias: repoAlias,
    },
  },
} satisfies NextConfig;

cefn avatar Apr 03 '25 09:04 cefn

This is a pretty frustrating experience. Turbopack was announced as stable and ready for dev back in October 2024. How can it be considered stable if it still doesn’t support tsconfig paths?

arodik avatar Jun 06 '25 14:06 arodik

This is a pretty frustrating experience. Turbopack was announced as stable and ready for dev back in October 2024. How can it be considered stable if it still doesn’t support tsconfig paths?

its now working properly... also fixed my image loader issue (latest version nextjs 15.3.3)

MeetBhingradiya avatar Jun 07 '25 05:06 MeetBhingradiya

its now working properly... also fixed my image loader issue (latest version nextjs 15.3.3)

I use 15.3.3 - it doesn't work for me and the error is unclear :(

arodik avatar Jun 07 '25 10:06 arodik

can you send me config ?

MeetBhingradiya avatar Jun 07 '25 11:06 MeetBhingradiya

@MeetBhingradiya I suspect there’s something in our tsconfig that’s breaking everything. I’ll debug it tomorrow and try to figure out what’s causing it. I created a fresh Next.js project, and I see that path aliases work there.

If it’s still not working after my investigation, I’ll create a small repo with a reproducible example so you can take a look. Thanks for your help :)

arodik avatar Jun 09 '25 17:06 arodik

@MeetBhingradiya I suspect there’s something in our tsconfig that’s breaking everything. I’ll debug it tomorrow and try to figure out what’s causing it. I created a fresh Next.js project, and I see that path aliases work there.

If it’s still not working after my investigation, I’ll create a small repo with a reproducible example so you can take a look. Thanks for your help :)

You can lookout for my "portfolio" repo you get it there next config, how i handled alias in turbopack, beside that i use webpack more but still its working with turbopack. @arodik

next.config.ts

MeetBhingradiya avatar Jun 10 '25 04:06 MeetBhingradiya

I've fixed it. We had rootDir and baseUrl pointed to src directory. Something like this:

{
  "compilerOptions": {
    "baseUrl": "src",
    "rootDir": "src",
    "paths": {
      "@demo/models/*": ["models/*"],
      "@demo/core/*": ["core/*"],
    }
  },
  "include": [
      "src",
      "next-env.d.ts"
    ],
}

I've simplified the config using the fresh nextjs project as a reference and now we have something like this and it works perfectly:

{
  "compilerOptions": {
    "paths": {
      "@demo/*": ["./src/*"],
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

Hope this will help people with similar problems :)

arodik avatar Jun 10 '25 14:06 arodik

@demo/

So we dont need to use

{
  turbopack: {
    resolveAlias: {
      '@': './',
      '@pages': './pages',
      '@public': './public',
    }
  }}

?

jarodcavalcante-locem avatar Aug 06 '25 13:08 jarodcavalcante-locem

@demo/

So we dont need to use

{
  turbopack: {
    resolveAlias: {
      '@': './',
      '@pages': './pages',
      '@public': './public',
    }
  }}

?

I think it depends on your luck and tsconfig setup 😅 You should try. This thing is still very confusing, probably needs some attention from nextjs team to make it better

arodik avatar Aug 07 '25 15:08 arodik

Verified that the initial issue happens because of a missing lockfile at the repository root. tsconfig paths is supported as documented: https://nextjs.org/docs/app/getting-started/installation#set-up-absolute-imports-and-module-path-aliases

If you find any cases it doesn't work as expected please open a separate issue with a reproduction. I checked @arodik's previous post with the config that didn't work and that works on the latest version of Next.js.

Going to close this issue as the original report is correctly failing to compile as it can't determine the application root to be the monorepo root since it's not a real workspaces setup.

timneutkens avatar Oct 19 '25 17:10 timneutkens

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

github-actions[bot] avatar Nov 03 '25 00:11 github-actions[bot]