Next.js Monorepo module resolution issues
Unanswered
Peruvian anchoveta posted this in #help-forum
Peruvian anchovetaOP
Hi everyone,
I'm facing an issue with a Next.js application in a pnpm monorepo workspace and would appreciate any help.
I have a monorepo with two packages:
I can successfully import and use code from the api package in the next package as long as the api package does not use TypeScript path aliases.
When I enable path aliases in the api package's tsconfig.json, the Next.js build and dev server process fails. TypeScript and ESLint in the next package recognize the imports and types without issues, but the Next.js build throws module resolution errors related to the path aliases used in the api package.
I want to be able to:
- Use path aliases in the api package for cleaner imports.
- Import the api package into the next package without having to build the api package separately.
- Let Next.js handle the build process, including resolving the path aliases used in the api package.
It's probably just some config issue from my side, but I've been pulling my hair out over this the last few days!
I've created a minimal repo to reproduce the issue. Any help would be greatly appreciated!
https://github.com/kyrregjerstad/next-monorepo
I'm facing an issue with a Next.js application in a pnpm monorepo workspace and would appreciate any help.
I have a monorepo with two packages:
.
├── next // Next.js application
│ └── src
└── api // Shared API logic
└── srcI can successfully import and use code from the api package in the next package as long as the api package does not use TypeScript path aliases.
When I enable path aliases in the api package's tsconfig.json, the Next.js build and dev server process fails. TypeScript and ESLint in the next package recognize the imports and types without issues, but the Next.js build throws module resolution errors related to the path aliases used in the api package.
I want to be able to:
- Use path aliases in the api package for cleaner imports.
- Import the api package into the next package without having to build the api package separately.
- Let Next.js handle the build process, including resolving the path aliases used in the api package.
It's probably just some config issue from my side, but I've been pulling my hair out over this the last few days!
I've created a minimal repo to reproduce the issue. Any help would be greatly appreciated!
https://github.com/kyrregjerstad/next-monorepo
4 Replies
Thrianta
Good question. This sort of config also drives me mad. In my case it’s definitely a skill issue.
I understand you want this as an import
import { someThing } from “@api/some-thing”
but as it stands you should be able to use this
import { someThing } from “@test/api/some-thing”
in my opinion this is clean enough. What do you think?
I understand you want this as an import
import { someThing } from “@api/some-thing”
but as it stands you should be able to use this
import { someThing } from “@test/api/some-thing”
in my opinion this is clean enough. What do you think?
Peruvian anchovetaOP
Hi @Thrianta, thanks for the quick reply! To clarify:
When i'm working in the api package in want my imports to be something like:
When i'm working in the next package I want to import it and use it as a normal package, if i have to specify a subpath, that's fine
Check out the repo i linked, if you got any ideas how to implement your solution I would love to hear it!
When i'm working in the api package in want my imports to be something like:
// ./api/src/index.ts
import { someThing } from '@/utils' // ✅
// or
import { someThing } from '@api/utils' // ✅
// exactly how it looks is not that important,
// as long as it's not
import { someThing } from '../../../../utils' // ❌When i'm working in the next package I want to import it and use it as a normal package, if i have to specify a subpath, that's fine
// ./next/src/page.tsx
import { someThing } from '@repo-name/api' // ✅
import { someThing } from '../../../api/src/utils/someThing' // ❌Check out the repo i linked, if you got any ideas how to implement your solution I would love to hear it!
Thrianta
Cool. I have run into this before and gave up since my ui package wasn't deeply nested.
I had an idea now and tested it out. It seems to be working in dev im not sure about a built app. Its pretty basic though. It basically involves creating path aliases in your api package that start with the name of your package like this:
This way, when the nextjs app sees this import it knows how to resolve it.
Heres a test repo for you to test it out.
https://github.com/john-prutton/turbo-path-alias-test/commit/57a5bb617ca14ca4b6f1782221f94b32df654e8a#diff-23d1c00ada88e4f7db71f0cd8959db1ec2a1442b48e818ec83f33d6d8f221845R5
Edit: unfortunately this doesnt compile -- see error below. I think you can fix this if you (1) set base path to the root of the monorepo, (2) can garuantee that every tsconfig will be on the same level - ie every tsconfig is the same number of "../" away from the root - except probably the base tsconf.
Edit 2: I might just be as cooked as I was when I first ran into this issue. I hope this gives you some ideas and that you can actually find a working suolution to this problem. If you do please let me know.
I had an idea now and tested it out. It seems to be working in dev im not sure about a built app. Its pretty basic though. It basically involves creating path aliases in your api package that start with the name of your package like this:
"@test/api/*": ["./src/*"]. This only gets added to the @test/api/tsconfig.json file.This way, when the nextjs app sees this import it knows how to resolve it.
Heres a test repo for you to test it out.
https://github.com/john-prutton/turbo-path-alias-test/commit/57a5bb617ca14ca4b6f1782221f94b32df654e8a#diff-23d1c00ada88e4f7db71f0cd8959db1ec2a1442b48e818ec83f33d6d8f221845R5
Edit: unfortunately this doesnt compile -- see error below. I think you can fix this if you (1) set base path to the root of the monorepo, (2) can garuantee that every tsconfig will be on the same level - ie every tsconfig is the same number of "../" away from the root - except probably the base tsconf.
▲ Next.js 14.2.6
│
│ Creating an optimized production build ...
│ Browserslist: caniuse-lite is outdated. Please run:
│ npx update-browserslist-db@latest
│ Why you should do it regularly: https://github.com/browserslist/update-db#readme
│ Failed to compile.
│
│ ../../packages/ui/src/button.tsx
│ Module not found: Package path ./uitil/cn is not exported from package C:\Users\johnr\Documents\web-dev\projects\turbo-path-alias-test\packages\ui (see exports field in C:\Users\johnr\Documents\web-dev
│ \projects\turbo-path-alias-test\packages\ui\package.json)
│
│ https://nextjs.org/docs/messages/module-not-foundEdit 2: I might just be as cooked as I was when I first ran into this issue. I hope this gives you some ideas and that you can actually find a working suolution to this problem. If you do please let me know.
Peruvian anchovetaOP
Yeah, I was attempting a similar solution myself in this branch
https://github.com/kyrregjerstad/next-monorepo/tree/solution-with-type-alias-in-root
but this comes with the caveat that you completely skip the package.json, and just import it directly through type aliases.
I'll let you know if I find a better solution! ✨
https://github.com/kyrregjerstad/next-monorepo/tree/solution-with-type-alias-in-root
but this comes with the caveat that you completely skip the package.json, and just import it directly through type aliases.
I'll let you know if I find a better solution! ✨