pm2
pm2 copied to clipboard
support "type": "module" (esm for node 13)
esm is no longer experimental in node 13, however pm2 does not read out "type": "module" from package.json, which means that esm imports/exports can not be used with pm2:
import { foo } from './foo.js';
^
SyntaxError: Unexpected token {
Some investigations: (node v13.3.0, pm2 4.2.0, MacOs 10.14.6)
- With "type":"module" in package.json
7|xxxx | (node:24598) Warning: require() of ES modules is not supported.
7|xxxx | require() of xxxx.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
7|xxxx | Instead rename loader-scanner.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from xxxxx/package.json.
7|xxxx | Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: xxxx.js
7|xxxx | at Object.Module._extensions..js (internal/modules/cjs/loader.js:1163:13)
- With .mjs extension
9|xxxx | Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: xxxxx.mjs
9|xxxx | at Module.load (internal/modules/cjs/loader.js:981:11)
9|xxxx | at Function.Module._load (internal/modules/cjs/loader.js:891:14)
- Without neither .mjs or "type":"module" :
8|xxxx | (node:24843) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
8|xxxx | xxxxx.js:10
8|xxxx | import { Run } from 'xxxxxxx';
8|xxxx | ^^^^^^
8|xxxx | SyntaxError: Cannot use import statement outside a module
8|xxxx | at wrapSafe (internal/modules/cjs/loader.js:1050:16)
8|xxxx | at Module._compile (internal/modules/cjs/loader.js:1098:27)
8|xxxx | at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:10)
The only workaround I've found so far is to keep esm is to use ESM loader with node args:
-r esm
(https://www.npmjs.com/package/esm)
But it's really slow compared to native node 13 loader
related to [https://github.com/Unitech/pm2/issues/4385]
NB: There is absolutely no require() in the code
Same here. I'm using .mjs and node 13, but esm workaround not even working for me. App runs fine using systemd daemon.
This is my first time using pm2 and I thought I was going insane! Have been googling about this for hours. I hope there will be a fix soon
A quick and dirty fix for pm2/lib/ProcessContainerFork.js : @Unitech
26 if (process.env.pm_exec_path)
27 // require('module')._load(process.env.pm_exec_path, null, true); //REPLACE
27 import(process.env.pm_exec_path); // (we don't use await here) //BY
Workaround: I'm using a 'custom loader' which is faster than esm-loader and use Node 13 native one. Its goal is to bypass ProcessContainerFork.js
We need to use node interpreter args: (here as api, but can be done using command line/ecosystem file)
- pm2.start(pm2Options)
pm2Options.interpreterArgs = '-- path/to/loader.js index.mjs'
// "--" is mandatory because we don't want node to parse our custom args.
// they will be placed before pm2's (ProcessContainerFork.js)
//
// index.mjs is our ES6 target script
// we should need "type":"module" in package.json if .mjs extension is not used
- loader.js
const moduleFile = process.cwd() + '/' + process.argv[2]
process.argv.splice(2, 2)
import (moduleFile)
Thanks for this report and suggestion, will dig this
Is this seriously not working?
@Unitech how can I help? This is pretty critical for my team as we're using modules in production.
It's been enabled officially by node, although still experimental (it works great on my end)
@Unitech Plz comment, this has been out for some time now and it has not been addressed
Will work on it by the next 7 days
Thanks, I've had to resort to using forever, but keen to switch back to pm2 once it's ready
Ok I landed the ES module support
Can anyone try it out please?
npm install Unitech/pm2#development -g
pm2 update
pm2 start app.mjs
Thank you!
I've checked:
pm2 start app.mjs- ok (package.type missing)pm2 start app.js- ok (package.type = 'module')pm2 start src/app.mjs- ok (package.type missing)pm2 start src/app.js- ERR_REQUIRE_ESM (package.type = 'module')
@Unitech
Works for me, but I had an error with this applying to saved processes.
I had to delete the process from pm2 and then reinstall it for it to work. Not a huge deal, but it might affect users wanting to move over to ESM
Release on pm2 4.2.2
npm install pm2@latest -g
pm2 update
It works ! thanks a lot
Just a detail: according to Node.js doc: https://nodejs.org/api/esm.html
The nearest parent package.json is defined as the first package.json found when searching in the current folder, that folder’s parent, and so on up until the root of the volume is reached.
Here pm2 is checking package.json in the current folder and it's first parent. In my case js is transpiled from src to a/deeper/folder then I have to copy project root's package.json to deployment folder, but it's not a big deal.
with ESM on windows my success only with:
pm2 start node -- src/index.js
@vitalets @r3gisc With node 12.18 and pm2 4.4.0 pm2 all combinations that you mentioned fails with ERR_REQUIRE_ESM error, which version of node did you use to verify that it's working?
This does not work with the docker pm2-runtime.
RUN yarn global add [email protected]
COPY . .
EXPOSE 8080
CMD [ "pm2-runtime", "index.js" ]
Gives:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /usr/src/app/index.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1154:13)
at Module.load (internal/modules/cjs/loader.js:986:32)
adding pm2 update doesn't fix either.
Per @vitaliytv suggestion I chcnged the following.
CMD [ "pm2-runtime", " node -- index.js" ]
Having issues with this again
@Unitech I'm getting Error [ERR_REQUIRE_ESM]: Must use import to load ES Module on pm2 4.4.0 with node 12.18.2.
I don't understand why need to switch to .mjs extension.
I don't understand why after I add "type": "module" it still not working.
I don't understand why need esm at the first place.
I don't understand after install esm, alias in .babelrc totally not working.
pm2 doesn't seems fix the problem but create more problem.
Can we reopen this issue. pm2 4.4.0 have the same problem again
why folks above said it works with v4.2.2. ? I have v4.4.1 installed but it still doesn't work
This test: https://github.com/Unitech/pm2/blob/0d44c41b07193bb793420ea23c476e020f8e99d5/test/e2e/esmodule.sh is passing
What is wrong with these tests? Let me know so I can fix whatever is missing
@Unitech I figured out what is wrong.
In pm2/lib/ProcessUtils.js:
try {
data = JSON.parse(fs.readFileSync(path.join(path.dirname(exec_path), 'package.json')))
if (data.type === 'module')
return true
else
return false
} catch(e) {
}
In my use case, index.js is in a subdirectory, such as app/lib/index.js. The issue is that path.join(path.dirname(exec_path) looks for package.json in the same directory as index.js, silently fails, and then can't find it.
Can you modify this to look for package.json at the root of the directory?
Something like this would do the trick.
I think the problem is that ESModules support is disabled for version below 13 (current LTS is 12.18.4) See here
@Unitech if pm2 calls the user scripts with require('userscript.js') in an wrapper rather than with process.fork('userscript.js') directly, this issue technically cannot be fixed, because node v13+ forbids require() on es module with type: module, which has nothing to do with whether the function require is hooked by -r esm.
it's needed to make a big change about how pm2 calls user scripts. it should be:
- calling user scripts with
process.forkdirectly - or calling user scripts with
import()in a wrapper
@Unitech it's still not working with "type": "module" in the package.json file, like in the picture below

I can confirm that the "type": "module" in package.json does not work properly on NodeJS LTS
I don't know why this isn't getting any priority, I literally can't use PM2 with ESM modules. Just discovered I also can't use the ecosystem file when type: "module" is enabled in package.json because it tries to import the file using require and errors out.
This is the reason ESM modules is erroring, changing this code resolves it for me:
https://github.com/Unitech/pm2/issues/4540#issuecomment-692296125
use babel to build file and run with pm2
Best workaround I've found for this is to change the name of the entry script from ending in ".js" to ending in ".mjs", not exactly an ideal solution, but it gets the job done as a temporary fix until this actually gets some attention
Using an Ecosystem file still doesn't work with ESM. pm2 needs to use import syntax or it could simply try to look for an Ecosystem file ending in .cjs.
For anyone having this issue, a really simple "workaround" is to just write your config file in YAML (see here). i.e. ecosystem.config.yaml and point your scripts to it.
Same feeling as @dhtree, pm2 is blocking our migration to ESM. It's frustrating.
If it can help someone, I found the following workaround :
pm2 start "node -- /path/to/app.js"
For this configuration:
pm2: 4.1.2 node: 14.16.1 (using n) package.json: has "type": "module" file extension: js os: centOS
With pm2#development:
app.js
// app.mjs
import { addTwo } from './addTwo.js';
// Prints: 6
console.log(addTwo(4));
addTwo.js
// addTwo.mjs
function addTwo(num) {
return num + 2;
}
export { addTwo };
package.json:
{
"name": "esm",
"version": "1.0.0",
"description": "",
"main": "addTwo.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
❯ node -v
v15.12.0
Then when I start:
pm2 start app.js
It works:
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
This is fantastic!
It works if the app.js file is at the root of the project, if it's deeper, doesn't work
Tried to start a script in children folder and it still works:

For anyone that wants another workaround, I have found that creating a separate entry script for the ecosystem file with extension .mjs works well, which then just imports the "real" entry script. ie having a file called entry.mjs which just contains:
import * as entry from './app.js';
Tried to start a script in children folder and it still works:
Try one level deeper... esm/deep/app.js I just tried and 1 level deep seems to work, 2 levels deep doesn't work :
pm2 start app.jsroot > workspm2 start modules/app.js> workspm2 start modules/api/app.js> not working
node version : 14.16.0
start script in package.json - cross-env NODE_ENV=development nodemon --es-module-specifier-resolution=node --experimental-modules --no-warnings src/common/bin/app.js
getting below error on running pm2 start npm -- run start
0|npm | Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/Programs/npm' is not supported resolving ES modules imported from /home/dhruv/.nvm/versions/node/v14.16.0/lib/node_modules/pm2/lib/ProcessContainerFork.js
0|npm | at finalizeResolution (internal/modules/esm/resolve.js:272:17)
0|npm | at moduleResolve (internal/modules/esm/resolve.js:699:10)
0|npm | at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
0|npm | at Loader.resolve (internal/modules/esm/loader.js:86:40)
0|npm | at Loader.getModuleJob (internal/modules/esm/loader.js:230:28)
0|npm | at Loader.import (internal/modules/esm/loader.js:165:28)
0|npm | at importModuleDynamically (internal/modules/cjs/loader.js:1006:27)
0|npm | at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:30:14)
0|npm | at Object.<anonymous> (/home/dhruv/.nvm/versions/node/v14.16.0/lib/node_modules/pm2/lib/ProcessContainerFork.js:30:16)
0|npm | at Module._compile (internal/modules/cjs/loader.js:1063:30) {
0|npm | code: 'ERR_UNSUPPORTED_DIR_IMPORT',
0|npm | url: 'file://Programs/npm'
0|npm | }
pm2 start "node -- index.js" and pm2 start index.js
seems to cause less error
If it can help someone, I found the following workaround :
pm2 start "node -- /path/to/app.js"
For this configuration:
pm2: 4.1.2 node: 14.16.1 (using n) package.json: has "type": "module" file extension: js os: centOS
This is what worked for me, since the app.js file was not in the root. many thanks!
What worked for me to make it run with ecosystem config was naming it ecosystem.config.cjs, and starting with pm2 start ecosystem.config.cjs
I'll echo @EskelCz in that renaming your ecoystem file to end with .cjs, and of course using common js module syntax inside of that file for requires and exports, seems to be working
If it can help someone, I found the following workaround :
pm2 start "node -- /path/to/app.js"
For this configuration:
pm2: 4.1.2 node: 14.16.1 (using n) package.json: has "type": "module" file extension: js os: centOS
This worked for me, thank you so much!
@Unitech Any updates with node 14 I am using pm2 v5 and still have the same problem.
I changed the config name to ecosystem.config.cjs then
pm2 start ecosystem.config.cjs
module.exports = {
apps : [{
name : "API",
script : "./src/Admin/API/Index.js"
}]
}
Throws the same error - Ive had to go back to nodemon :(
esm is natively supported, stable in all active LTS distributions. Is this not something pm2 ever plans to support?
Working for me with a package.json inside the route.
if you have modules/app.js, just add a modules/package.json
package.json
{
"version": "1.0.0",
"type": "module"
}
@Unitech Any updates with
node 14I am usingpm2 v5and still have the same problem.I changed the config name to
ecosystem.config.cjsthenpm2 start ecosystem.config.cjs
Has the problem been solved?
Yes the problem is solved. This solution worked for me.
чт, 6 янв. 2022 г., 17:35 Ramsay Jiang @.***>:
@Unitech https://github.com/Unitech Any updates with node 14 I am using pm2 v5 and still have the same problem.
I changed the config name to ecosystem.config.cjs then
pm2 start ecosystem.config.cjs
Has the problem been solved?
— Reply to this email directly, view it on GitHub https://github.com/Unitech/pm2/issues/4540#issuecomment-1006639063, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFMLXHTVTJ7LOWNYJTMJIL3UUWSEDANCNFSM4JVW4OYA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you are subscribed to this thread.Message ID: @.***>
I still get many errors, I use node 17.3, pm2 5.1.2 and ESM...
Yup, same here. After many years working with pm2 and commonjs, changing to ESM and bumping into this is really frustrating.
EDIT: solved using exosystem.config file with CJS extension as mentioned in some posts above pm2 start ecosystem.config.cjs
I think this comment should get a prize:
really simple "workaround" is to just write your config file in YAML
Thank you so much, @adamhl8 !
Like others I was frustrated with having issues with pm2. After reading:
Tried to start a script in children folder and it still works:
Try one level deeper... esm/deep/app.js I just tried and 1 level deep seems to work, 2 levels deep doesn't work :
pm2 start app.jsroot > workspm2 start modules/app.js> workspm2 start modules/api/app.js> not working
as well as:
Working for me with a package.json inside the route. if you have
modules/app.js, just add amodules/package.json
package.json{ "version": "1.0.0", "type": "module" }
I was able to work around the problem by creating a "package.json" file 1 level away from the script I was calling in the "ecosystem.config.cjs" and that worked for me.
/root
|_ ecosystem.config.cjs
|_ /src
|_ package.json
|_ /services
|_ SCRIPT_NAME.js <- this is what ecosys is calling
So it appears the issue is that it won't traverse more than one level if you are using ESM. Just my two cents FWIW.
Thanks @HRK44, @fvilar.
os: Ubuntu node: v16.3.0 pm2: 5.2.0
Ok, so "type": "module", is given. In the docs you need to read very closely to notice the mention of being able to use a json config file. And you need to go right to the ecosystem config file examples to reveal that even yaml is supported.
This ecosystem.config.js doesn't work in this case, yet it's all you see in the docs:
module.exports = {
apps: [{
name: "app1",
script: "./index.js"
}]
}
But this ecosystem.config.json works:
{
"apps": [{
"name": "app1",
"script": "./index.js"
}]
}
Also this ecosystem.config.yaml works:
apps:
- name : 'app1'
script: './index.js'
If you really want to stick with a JS file, this ecosystem.config.es6.js works as well:
export default {
apps: [{
name: "app1",
script: "./index.js"
}]
}
I'm not saying the docs are bad, but they certainly don't cover every new kind of possibility.
Bonus:
{
"name": "app1",
"script": "./index.js"
}
Probably the easisest json config if you only have 1 app to config and have managed by pm2.
2 and a half year with no luck? That's a shame :(
Anyway, the simplest solution is the one from @nickpharrison
Near your index.js or whatever create entry.mjs file with import "./index.js" and run it instead. It just works, the .mjs extension is what forces node into ESM mode.
I was starting to think that pm2 is superfluous. You can better manage integrating directly with systemd
Il ven 3 giu 2022, 21:33 Jacek Nowacki @.***> ha scritto:
2 and a half year with no luck? That's a shame :(
Anyway, the simplest solution is the one from @nickpharrison https://github.com/nickpharrison
Near your index.js or whatever create entry.mjs file with import "./index.js" and run it instead. It just works, the .mjs extension is what forces node into ESM mode.
— Reply to this email directly, view it on GitHub https://github.com/Unitech/pm2/issues/4540#issuecomment-1146295891, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADXQ34KTVHWV4LLLPHHCTLVNJMW3ANCNFSM4JVW4OYA . You are receiving this because you commented.Message ID: @.***>
was starting to think that pm2 is superfluous. You can better manage
100% agreed, pm2 (and other service wrappers) aren't needed in 2022.