pm2-node-serviceslisted
Install: claude install-skill Mixard/fable-pack
# PM2 Service Configs
## Config file
PM2 config in an ESM project ("type": "module") needs the `.cjs` extension: `ecosystem.config.cjs`, CommonJS `module.exports`.
```javascript
module.exports = {
apps: [
{
name: 'web-3000',
cwd: './packages/web',
script: 'node_modules/vite/bin/vite.js',
args: '--port 3000',
env: { NODE_ENV: 'development' }
},
{
name: 'api-8000',
cwd: './backend',
script: 'start.cjs',
env: { PYTHONUNBUFFERED: '1' }
}
]
}
```
On Windows, add `interpreter: 'C:/Program Files/nodejs/node.exe'` to each app — PM2's default interpreter resolution is unreliable there.
## Framework entry points
Pointing `script` at the framework's real bin file (not an npm script) keeps PM2 in control of the actual process:
| Framework | script | args | Default port |
|-----------|--------|------|--------------|
| Vite | `node_modules/vite/bin/vite.js` | `--port {port}` | 5173 |
| Next.js | `node_modules/next/dist/bin/next` | `dev -p {port}` | 3000 |
| Nuxt | `node_modules/nuxt/bin/nuxt.mjs` | `dev --port {port}` | 3000 |
| Express/Node | `src/index.js` or `server.js` | — | 3000 |
| FastAPI (via wrapper) | `start.cjs` | — | 8000 |
## Python under PM2
Running Python directly via PM2 `interpreter` is flaky on Windows; a Node wrapper script is the reliable route:
```javascript
// backend/start.cjs
const { spawn } = require('child_process');
const proc = spawn('python', ['-m', 'uvicorn', 'app.main:app', '-