Search code examples
mongoosenext.js

Unable to use Mongoose 7 with NextJS 13


I am using Nextjs 13.4.7 with mongoose 7 and have made necessary configurations to my next.config.js as give by mongoose as shown:

/** @type {import('next').NextConfig} */

module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      use: ['@svgr/webpack'],
    });
    config.experiments = { ...config.experiments, topLevelAwait: true };
    return config
  },
  experimental: {
    serverComponentsExternalPackages: ["mongoose"],
    appDir: true
  },
}

However it still gives lot module import errors as follows:

Module not found: Can't resolve 'kerberos' in '/home/krush/portfolioblog/blog/node_modules/mongodb/lib'

Import trace for requested module:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js

./node_modules/mongodb/lib/deps.js
Module not found: Can't resolve '@mongodb-js/zstd' in '/home/krush/portfolioblog/blog/node_modules/mongodb/lib'

Import trace for requested module:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js

./node_modules/mongodb/lib/deps.js

Module not found: Can't resolve 'aws4' in '/home/krush/portfolioblog/blog/node_modules/mongodb/lib'

Import trace for requested module:
./node_modules/mongodb/lib/deps.js
./node_modules/mongodb/lib/index.js
./node_modules/mongoose/lib/index.js
./node_modules/mongoose/index.js
./lib/dbConnect.js
./app/posts/[postId]/page.js

How do I fix this? Can someone provide the proper configuration that would resolve this error?

PS. This error was because of the NextJS rule that we cannot use client components ('use client' directive) with server components.


Solution

  • Turns out you can't use mongoose in client component(having "use client") data fetching as it involves mongoose requiring mongodb connection URI env variable which cannot be accessed within client component. This is how I solved it:

    Erroneous method

    - app/
      - posts/
         - [postId]
            - page.js
    

    Code of my page.js component using mongoose queries that is a client component to use React state etc.

    'use client';
    import Posts from '@/models/post';
    import dbConnect from '@/lib/dbConnect';
    
    async function fetchPost(postId) {
       // MONGODB_URI is being accessed by dbConnect() which is not possible
       await dbConnect();
         const postData = await Posts.findById(postId);
    
         return postData;
    }
    
    
    export default async function Component({params: {postId}}) {
       const postData = await fetchPost();
    
       return <div>{postData.title}</div>
    }
    

    Fixed method

    New directory structure.

    • page.js becomes a server component with data passed on to child component as props
    • PostComponent handles the client functionalities and now can access Reach functionalities like states.
    - app/
      - posts/
         - [postId]
            - page.js
            - PostComponent.js
    

    Structure of my page.js component using mongoose queries

    import Posts from '@/models/post';
    import dbConnect from '@/lib/dbConnect';
    import PostComponent from './PostComponent';
    
    async function fetchPost(postId) {
       // MONGODB_URI is being accessed by dbConnect() which is not possible
       await dbConnect();
         const postData = await Posts.findById(postId);
    
         return postData;
    }
    
    export default async function Component({params: {postId}}) {
       const postData = await fetchPost();
    
       return <div><PostComponent postData={postData} /></div>
    }
    

    PS. I also had an issue where I was unable to use env variables without NEXT_APP_ prefix. This answer also solves those issues.