"@" Path Alias in Turborepo Build Causing Module Not Found Error

I’m using a Turborepo monorepo setup where my UI package’s tsconfig.json defines path aliases. When I configure the alias as "@rhu-ii/ui/*": ["./src/*"] and update my component import to:

import { cn } from '@rhu-ii/ui/lib/utils'

the build runs successfully. However, if I change the alias in tsconfig.json to "@/*": ["./src/*"] and update the import accordingly:

import { cn } from '@/lib/utils'

I get a build error:

bun run build
$ turbo run build
turbo 2.4.4

 WARNING  Unable to calculate transitive closures: No lockfile entry found for 'typescript@5.8.2'
• Packages in scope: @rhu-ii/eslint, @rhu-ii/prettier, @rhu-ii/tailwind, @rhu-ii/typescript, @rhu-ii/ui, docs, web
• Running build in 7 packages
• Remote caching disabled
┌ docs#build > cache miss, executing ea08ab36ba3c7112
│ $ next build
│    ▲ Next.js 15.2.4
│
│    Creating an optimized production build ...
└────>
┌ web#build > cache miss, executing 164309d43cdea666
│ $ next build
│    ▲ Next.js 15.2.4
│
│    Creating an optimized production build ...
│ Failed to compile.
│
│ ../../packages/ui/src/components/button.tsx
│ Module not found: Can't resolve '@/src/lib/utils'
│
│ https://nextjs.org/docs/messages/module-not-found
│
│ Import trace for requested module:
│ ./app/page.tsx
│
│
│ > Build failed because of webpack errors
│ error: script "build" exited with code 1
│
│ command finished with error: command (C:\Users\craft\Desktop\Dev\rhu-ii\apps\web) C:\Users\craft\.bun\
│ bin\bun.exe run build exited (1)
└────>
  × Internal errors encountered: unable to determine why task exited

error: script "build" exited with code 1

Here’s my tsconfig.json of my packages/ui

{
  "extends": "@rhu-ii/typescript/internal-library.json",
  "compilerOptions": {
    "jsx": "preserve",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

And here’s my internal-library.json

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "outDir": "${configDir}/dist",
    "module": "Preserve",
    "moduleResolution": "Bundler"
  }
}

And here’s my package.json of my packages/ui

{
  "name": "@rhu-ii/ui",
  "version": "0.0.0",
  "private": true,
  "exports": {
    "./lib/*": "./src/lib/*.ts",
    "./components/*": "./src/components/*.tsx",
    "./hooks/*": "./src/hooks/*.ts"
  },
  "scripts": {
    "ui-add": "bunx --bun shadcn@latest add",
    "postui-add": "prettier src --write --list-different",
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component",
    "check-types": "tsc --noEmit",
    "clean": "git clean -xdf .cache .turbo node_modules"
  },
  "devDependencies": {
    "@rhu-ii/eslint": "*",
    "@rhu-ii/typescript": "0.0.0",
    "@rhu-ii/prettier": "*",
    "@rhu-ii/tailwind": "*",
    "@turbo/gen": "^2.4.4",
    "@types/node": "^22.13.10",
    "@types/react": "19.0.12",
    "@types/react-dom": "19.0.4",
    "eslint": "^9.23.0",
    "typescript": "^5.8.2"
  },
  "dependencies": {
    "@hookform/resolvers": "^5.0.1",
    "@radix-ui/react-accordion": "^1.2.3",
    "@radix-ui/react-alert-dialog": "^1.1.6",
    "@radix-ui/react-aspect-ratio": "^1.1.2",
    "@radix-ui/react-avatar": "^1.1.3",
    "@radix-ui/react-checkbox": "^1.1.4",
    "@radix-ui/react-collapsible": "^1.1.3",
    "@radix-ui/react-context-menu": "^2.2.6",
    "@radix-ui/react-dialog": "^1.1.6",
    "@radix-ui/react-dropdown-menu": "^2.1.6",
    "@radix-ui/react-hover-card": "^1.1.6",
    "@radix-ui/react-label": "^2.1.2",
    "@radix-ui/react-menubar": "^1.1.6",
    "@radix-ui/react-navigation-menu": "^1.2.5",
    "@radix-ui/react-popover": "^1.1.6",
    "@radix-ui/react-progress": "^1.1.2",
    "@radix-ui/react-radio-group": "^1.2.3",
    "@radix-ui/react-scroll-area": "^1.2.3",
    "@radix-ui/react-select": "^2.1.6",
    "@radix-ui/react-separator": "^1.1.2",
    "@radix-ui/react-slider": "^1.2.3",
    "@radix-ui/react-slot": "^1.1.2",
    "@radix-ui/react-switch": "^1.1.3",
    "@radix-ui/react-tabs": "^1.1.3",
    "@radix-ui/react-toggle": "^1.1.2",
    "@radix-ui/react-toggle-group": "^1.1.2",
    "@radix-ui/react-tooltip": "^1.1.8",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "cmdk": "^1.1.1",
    "date-fns": "^4.1.0",
    "embla-carousel-react": "^8.5.2",
    "input-otp": "^1.4.2",
    "lucide-react": "^0.487.0",
    "next-themes": "^0.4.6",
    "react": "^19.1.0",
    "react-day-picker": "8.10.1",
    "react-dom": "^19.1.0",
    "react-hook-form": "^7.55.0",
    "react-resizable-panels": "^2.1.7",
    "recharts": "^2.15.1",
    "sonner": "^2.0.3",
    "tailwind-merge": "^3.1.0",
    "vaul": "^1.1.2",
    "zod": "^3.24.2"
  },
  "prettier": "@rhu-ii/prettier"
}

This error occurs during the Next.js build in the web app.
Can anyone explain why this happens and suggest a solution?

This is one of the limitations of Just-in-Time Packages. TypeScript path aliases don’t work, and this is expected behavior. We encourage the use of Node.js subpath imports instead.

I see, but I tried also to convert into Compiled Packages here’s my packages/ui/package.json

  "exports": {
    "./components/*": {
      "types": "./dist/components/*.tsx",
      "default": "./dist/components/*.jsx"
    },
    "./lib/*": {
      "types": "./dist/lib/*.ts",
      "default": "./dist/lib/*.js"
    },
    "./hooks/*": {
      "types": "./dist/hooks/*.ts",
      "default": "./dist/hooks/*.js"
    }
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsc",
    "ui-add": "bunx --bun shadcn@latest add",
    "postui-add": "prettier src --write --list-different",
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component",
    "check-types": "tsc --noEmit",
    "clean": "git clean -xdf .cache .turbo node_modules"
  },

Still has that build error:

bun run build
$ turbo run build
turbo 2.4.4

 WARNING  Unable to calculate transitive closures: No lockfile entry found for 'eslint-plugin-react@7.37.4'
• Packages in scope: @rhu-ii/eslint, @rhu-ii/prettier, @rhu-ii/tailwind, @rhu-ii/typescript, @rhu-ii/ui, docs, web
• Running build in 7 packages
• Remote caching disabled
┌ @rhu-ii/ui#build > cache miss, executing 545fe1fa63ac2687
│ $ tsc
└────>
┌ docs#build > cache miss, executing b9419416840265ed
│ $ next build
│    ▲ Next.js 15.2.4
│
│    Creating an optimized production build ...
└────>
┌ web#build > cache miss, executing a67f25ebc28b5a3f
│ $ next build
│    ▲ Next.js 15.2.4
│
│    Creating an optimized production build ...
│ Failed to compile.
│
│ ../../packages/ui/dist/components/button.jsx
│ Module not found: Can't resolve '@/lib/utils'
│
│ https://nextjs.org/docs/messages/module-not-found
│
│ Import trace for requested module:
│ ./app/page.tsx
│
│
│ > Build failed because of webpack errors
│ error: script "build" exited with code 1
│
│ command finished with error: command (C:\Users\craft\Desktop\Dev\rhu-ii\apps\web) C:\Users\craft\.bun\
│ bin\bun.exe run build exited (1)
└────>
  × Internal errors encountered: unable to determine why task exited

error: script "build" exited with code 1

Is there a solution for this? or the best is to use the Node.js subpath imports when creating internal library?

But when I configure the alias as "@rhu-ii/ui/*": ["./src/*"] the build runs successfully.