Nx.js & next.js build error, can't find a user config at /var/task/next-i18next.config.js

In a package-based next.js project based on nx.js, I encountered the following error:

next-i18next was unable to find a user config at /var/task/next-i18next.config.js

The project directory structure is as follows:

.
├── dist    # packages/web build output dir
├── nx.json
├── package-lock.json
├── package.json
├── packages
  ├── hooks # hooks library
  ├── icons # icons library
  ├── web   # next.js web app
    ├── babel.config.json
    ├── configs
    ├── next-env.d.ts
    ├── next-i18next.config.js
    ├── next.config.js
    ├── package.json
    ├── pages
    ├── project.json
    ├── public
    ├── styles
    ├── theme
    ├── tsconfig.json
    ├── scripts
    └── tsconfig.base.json
  • nx.js: 15.8.9
  • next.js: 13.1.1
  • node: 18.12.1

The scripts section in the package.json file in the root directory is as follows:

{
  "scripts": {
    "dev": "nx run web:serve --development --verbose",
    "build": "nx run web:build --production --verbose && node ./scripts/copyFiles.js"
  }
}

The project.json file for the web application in nx is configured as follows:

{
  "name": "web",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "packages/web",
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nrwl/next:build",
      "outputs": [
        "{options.outputPath}"
      ],
      "defaultConfiguration": "production",
      "options": {
        "root": "packages/web"
      },
      "configurations": {
        "development": {
          "outputPath": "dist/web"
        },
        "production": {
          "outputPath": "dist/web"
        },
        "staging": {
          "outputPath": "dist/web"
        },
        "beta": {
          "outputPath": "dist/web"
        }
      }
    },
    "export": {
      "executor": "@nrwl/next:export",
      "options": {
        "buildTarget": "web:build:production"
      }
    }
  }
}

next-i18next.config.js:

const configs = require('./configs');
const locales = Object.keys(configs.languages);
const path = require('path');

const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';

const getLocalePath = () => {
    if (isProd) {
        return path.resolve('./public/locales');
    }

    if (isDev) {
        return configs.isServer
            ? require('path').resolve('./packages/web/public/locales')
            : '/locales';
    }

    return path.resolve('./public/locales');
};

module.exports = {
    // debug: isDev,
    i18n: {
        localeDetection: false,
        defaultLocale: 'en',
        locales,
    },
    defaultNS: 'common',
    lowerCaseLng: true,
    localePath: getLocalePath(),
    nsSeparator: '::',
    keySeparator: '::',
    reloadOnPrerender: true,
    // Do not load a fallbakick.  We'll just use the key as the fallback.
    fallbackLng: false,
    // Empty strings should be invalid, so we can fallback to the message key
    returnEmptyString: false,
};

next.config.js:

const {withNx} = require('@nrwl/next/plugins/with-nx');
process.env.I18NEXT_DEFAULT_CONFIG_PATH = `${__dirname}/next-i18next.config.js`;
const {i18n} = require('./next-i18next.config');
const path = require('path');
const configs = require('./configs');

/**
 * @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
 **/
const nextConfig = {
    i18n,
    nx: {
        svgr: false,
    },
    rewrites: async () => [
        {
            source: '/api/:path*',
            destination: `${configs.env.endpoints.baseAPI}/api/:path*`, // Proxy to Backend
        },
    ],
    transpilePackages: ['@crownbit/icons'],
    experimental: {
        largePageDataBytes: 1000 * 1000,
    },
    useFileSystemPublicRoutes: true,
    reactStrictMode: true,
    env: {
        MOON_ENV: process.env.NX_MOON_ENV,
        LATEST_GIT_HASH: process.env.LATEST_GIT_HASH,
    },
    sentry: {},
};

const {withSentryConfig} = require('@sentry/nextjs');

async function withCustom(phase) {
    const nxConfig = withNx(nextConfig);
    const c = await nxConfig(phase);
    return withSentryConfig(
        c,
        {
            silent: true,
            project: 'javascript-nextjs',
        },
        {
            widenClientFileUpload: true,

            transpileClientSDK: true,

            tunnelRoute: '/monitoring',

            hideSourceMaps: true,

            disableLogger: true,
        },
    );
}

module.exports = withCustom;

Because nx cannot output the build files in the source directory, the output directory for the web project is set to the
dist directory in the root directory. However, nx does not copy the next-i18next.config.js and configs directories to
the dist directory. Therefore, I wrote a script to copy the next-i18next.config.js and configs directories to the dist
directory:

const fs = require('fs-extra');

function copyFileOrDirectory(source, destination) {
    try {
        fs.copySync(source, destination);
        console.log(`${source} Copy successful!`);
    } catch (err) {
        console.error(`${source} Copy failed:`, err);
    }
}

console.log('Preparing to copy file or directory');
copyFileOrDirectory('./packages/web/configs', './dist/web/configs');

copyFileOrDirectory(
    './packages/web/next-i18next.config.js',
    './dist/web/next-i18next.config.js',
);

process.exit(0);

This script works correctly on the local development environment and self-managed servers. However, when deploying to Netlify, I encountered the following error:

next-i18next was unable to find a user config at /var/task/next-i18next.config.js

Does anyone know about this issue? Are there any recommended solutions?

Maybe try including that file in functions manually: How to Include Files in Netlify Serverless Functions?

I added the netlify.toml file to the root of the project and configured it as follows:

# Include all files in all functions
[functions]
  included_files = ["packages/web/configs/**", "packages/web/next-i18next.config.js"]

but it doesn’t work properly and the online environment still reports errors, is there any other solution?

Sorry for the delay. Is it possible for you to share a minimal repo so we can check the issue?

hi,hrishikesh,thank you very much for your reply.

I rebuilt a minimal repo: GitHub - onejustone/web

and netlify preview link: https://main--flourishing-khapse-9514a8.netlify.app/

Please help us with the deployment process as soon as possible and we will consider using the Enterprise version.

Hey @groot,

Thank you for that repo, that was super helpful! I was able to try some changes and also made some progress, but still not enough to get the site working. So I have asked the devs to take a look and comment what kind of a configuration can get this working.

OK, I’m waiting for your reply, hopefully we can get a grip.

Hi, I am having the same issue with an NX project. Did you manage to solve it? @hrishikesh

This issue did not reach a solution, but it’s also about a year old and a lot has changed since then. If you need help @diegoesolorzano, please share your site’s details.

Yes, thanks, but I am having the same issue. It’s a Nx project, nextjs 12. i18next (serverSideTranslations) is working on getStaticProps, but when using getServerSideProps I am getting “next-i18next was unable to find a user config at /var/task/next-i18next.config.js”

And even it’s a year old issue I haven’t find a solution for this.

Without knowing the site or the repo, we cannot offer any help. Can you provide your site’s details?

Sure, How can I share the repo? It’s a private project tough

We’d first recommend migrating to Next.js 13.5+ and trying out the Next.js Runtime v5. Runtime v4 is in maintenance mode, so even if we find this as a bug, we would likely not be able to do anything about it.

Ok. I managed to fix this issue. Drop it here just in case anyone needs the fix.
Just place the next-i18next.config.js in the same directory than next.config.js, and this should be the root of nextjs app, not in the NX root project folder.