forever、nodemon、pm2 和 supervisor 都是用于管理 Node.js 进程生命周期的工具,但它们的定位截然不同。nodemon 专为开发环境设计,通过监听文件变化自动重启服务以提升开发效率;pm2 是生产级进程管理器,提供集群模式、日志管理和进程守护;forever 是早期的保活工具,功能较为基础;supervisor 已停止维护,属于历史遗留方案。
在 Node.js 生态中,保持服务持续运行和在开发时自动重启是两个核心需求。forever、nodemon、pm2 和 supervisor 都试图解决这个问题,但它们的架构设计和适用场景有显著差异。作为架构师,我们需要根据环境(开发 vs 生产)和功能需求(保活 vs 集群)来做出选择。
这四个工具可以分为两类:开发工具和生产工具。
nodemon 纯粹为开发体验设计。
# nodemon: 启动开发服务器
npx nodemon app.js
pm2 是生产级进程管理器。
# pm2: 启动生产进程
pm2 start app.js --name "my-app" -i max
forever 是早期的保活工具。
# forever: 启动脚本保活
forever start app.js
supervisor 是历史遗留工具。
nodemon 取代。# supervisor: 启动(已不推荐)
supervisor app.js
理解它们何时重启进程至关重要。
nodemon 基于文件变更触发重启。
node_modules)。// nodemon.json 配置示例
{
"watch": ["src"],
"ext": "ts,json",
"ignore": ["src/tests"],
"exec": "ts-node ./index.ts"
}
pm2 基于进程状态触发重启。
--watch),但生产环境通常关闭此功能以防意外重启。// ecosystem.config.js 配置示例
module.exports = {
apps: [{
name: "app",
script: "./app.js",
watch: false, // 生产环境通常关闭 watch
max_memory_restart: "500M"
}]
};
forever 基于进程退出触发重启。
# forever: 仅保活,不监听文件变化
forever start -l forever.log -o out.log -e err.log app.js
supervisor 基于文件变更触发重启。
nodemon,但配置选项较少,灵活性差。# supervisor: 监听变化重启
supervisor --watch lib,config app.js
在生产环境中,单进程 Node.js 应用无法利用多核 CPU,且日志管理至关重要。
pm2 提供完整的集群模式。
# pm2: 开启集群模式,自动根据 CPU 核心数调整
pm2 start app.js -i max
# pm2: 查看日志
pm2 logs
forever 不支持原生集群模式。
# forever: 手动启动多个实例(需自行管理端口)
forever start -p 3000 app.js
forever start -p 3001 app.js
nodemon 不具备生产特性。
# nodemon: 无集群参数,仅单进程
nodemon app.js
supervisor 不具备生产特性。
# supervisor: 无相关生产参数
supervisor app.js
配置方式反映了工具的现代化程度。
pm2 支持声明式配置。
ecosystem.config.js 管理所有应用。// ecosystem.config.js
module.exports = {
apps: [{
env: {
NODE_ENV: "development",
},
env_production: {
NODE_ENV: "production",
}
}]
};
nodemon 支持 JSON 配置。
nodemon.json 简单易读。// nodemon.json
{
"restartable": "rs",
"verbose": true
}
forever 主要依赖命令行参数。
# forever: 通过参数配置日志路径
forever start -l /var/log/forever.log app.js
supervisor 依赖命令行参数。
# supervisor: 通过参数配置
supervisor --no-restart-on path-change app.js
选择工具时,社区活跃度是长期稳定性的保障。
| 工具 | 状态 | 风险 | 建议 |
|---|---|---|---|
pm2 | ✅ 活跃维护 | 低 | 生产环境首选 |
nodemon | ✅ 活跃维护 | 低 | 开发环境首选 |
forever | ⚠️ 维护缓慢 | 中 | 仅限旧项目迁移 |
supervisor | ❌ 停止维护 | 高 | 避免使用 |
supervisor 的 npm 页面已明确标记为不再维护。使用它意味着你将无法获得安全更新,且可能面临与新版本 Node.js 的兼容性问题。
forever 虽然仍可运行,但功能迭代已停滞。对于需要现代运维特性(如 Docker 集成、云部署)的项目,pm2 是更稳妥的选择。
开发阶段:
毫不犹豫地选择 nodemon。它与 VS Code 等编辑器集成良好,配置简单,能显著提升编码效率。不要在生产流程中依赖它。
# package.json 脚本示例
"scripts": {
"dev": "nodemon src/index.js",
"start": "pm2 start ecosystem.config.js"
}
生产阶段:
必须选择 pm2。它的集群模式能显著提升吞吐量,守护机制确保服务高可用。配合 pm2 deploy 可以实现简单的零停机部署。
遗留系统:
如果遇到 forever 或 supervisor,制定迁移计划。supervisor 应优先替换为 nodemon。forever 应逐步迁移至 pm2 以获得更好的可观测性。
| 特性 | nodemon | pm2 | forever | supervisor |
|---|---|---|---|---|
| 主要场景 | 开发 | 生产 + 开发 | 生产 (旧) | 开发 (旧) |
| 文件监听 | ✅ 原生支持 | ✅ 可选 (--watch) | ❌ 不支持 | ✅ 原生支持 |
| 崩溃重启 | ✅ (视为文件变动) | ✅ 核心功能 | ✅ 核心功能 | ✅ (视为文件变动) |
| 集群模式 | ❌ | ✅ 支持 | ❌ | ❌ |
| 日志管理 | ❌ (输出到 stdout) | ✅ 高级管理 | ⚠️ 基础重定向 | ⚠️ 基础重定向 |
| 维护状态 | ✅ 活跃 | ✅ 活跃 | ⚠️ 缓慢 | ❌ 停止 |
在现代 Node.js 架构中,nodemon + pm2 是标准组合。开发时用 nodemon 享受热重载,部署时用 pm2 确保稳定运行。forever 和 supervisor 属于上一代工具链,除非维护旧系统,否则不应出现在新项目的依赖列表中。
选择 forever 仅用于维护旧项目或极其简单的脚本保活。在新项目中不推荐使用,因为它的功能集不如 pm2 丰富,且社区活跃度较低。如果你的服务器环境非常受限且只需最基础的“挂了重启”,它仍可用。
选择 nodemon 用于本地开发环境。当你需要修改代码后自动重启 Node.js 服务,且不需要生产级的高可用或集群功能时,它是最佳选择。它配置简单,社区支持好,是前端开发者的标准开发工具。
选择 pm2 用于生产环境部署。当你需要确保应用崩溃后自动重启、利用多核 CPU 运行集群模式、或需要统一的日志管理和监控仪表盘时,pm2 是行业标准。它也支持开发模式,但主要优势在生产。
不建议在任何新项目中选择 supervisor。该包已长期停止维护,存在未修复的安全隐患和兼容性问题。应迁移至 nodemon(开发)或 pm2(生产)以获得更好的支持和功能。
A simple CLI tool for ensuring that a given script runs continuously (i.e. forever). Note that this project currently fully depends on the community for implementing fixes and new features. For new installations we encourage you to use pm2 or nodemon
$ [sudo] npm install forever -g
Note: If you are using forever programmatically you should install forever-monitor.
$ cd /path/to/your/project
$ [sudo] npm install forever-monitor
There are two ways to use forever: through the command line or by using forever in your code. Note: If you are using forever programatically you should install forever-monitor.
You can use forever to run scripts continuously (whether it is written in node.js or not).
Example
forever start app.js
Options
$ forever --help
usage: forever [action] [options] SCRIPT [script-options]
Monitors the script specified in the current process or as a daemon
actions:
start Start SCRIPT as a daemon
stop Stop the daemon SCRIPT by Id|Uid|Pid|Index|Script
stopall Stop all running forever scripts
restart Restart the daemon SCRIPT
restartall Restart all running forever scripts
list List all running forever scripts
config Lists all forever user configuration
set <key> <val> Sets the specified forever config <key>
clear <key> Clears the specified forever config <key>
logs Lists log files for all forever processes
logs <script|index> Tails the logs for <script|index>
columns add <col> Adds the specified column to the output in `forever list`. Supported columns: 'uid', 'command', 'script', 'forever', 'pid', 'id', 'logfile', 'uptime'
columns rm <col> Removed the specified column from the output in `forever list`
columns set <cols> Set all columns for the output in `forever list`
columns reset Resets all columns to defaults for the output in `forever list`
cleanlogs [CAREFUL] Deletes all historical forever log files
options:
-m MAX Only run the specified script MAX times
-l LOGFILE Logs the forever output to LOGFILE
-o OUTFILE Logs stdout from child script to OUTFILE
-e ERRFILE Logs stderr from child script to ERRFILE
-p PATH Base path for all forever related files (pid files, etc.)
-c COMMAND COMMAND to execute (defaults to node)
-a, --append Append logs
-f, --fifo Stream logs to stdout
-n, --number Number of log lines to print
--pidFile The pid file
--uid DEPRECATED. Process uid, useful as a namespace for processes (must wrap in a string)
e.g. forever start --uid "production" app.js
forever stop production
--id DEPRECATED. Process id, similar to uid, useful as a namespace for processes (must wrap in a string)
e.g. forever start --id "test" app.js
forever stop test
--sourceDir The source directory for which SCRIPT is relative to
--workingDir The working directory in which SCRIPT will execute
--minUptime Minimum uptime (millis) for a script to not be considered "spinning"
--spinSleepTime Time to wait (millis) between launches of a spinning script.
--colors --no-colors will disable output coloring
--plain Disable command line colors
-d, --debug Forces forever to log debug output
-v, --verbose Turns on the verbose messages from Forever
-s, --silent Run the child script silencing stdout and stderr
-w, --watch Watch for file changes
--watchDirectory Top-level directory to watch from
--watchIgnore To ignore pattern when watch is enabled (multiple option is allowed)
-t, --killTree Kills the entire child process tree on `stop`
--killSignal Support exit signal customization (default is SIGKILL),
used for restarting script gracefully e.g. --killSignal=SIGTERM
Any console output generated after calling `forever stop/stopall` will not appear in the logs
-h, --help You're staring at it
[Long Running Process]
The forever process will continue to run outputting log messages to the console.
ex. forever -o out.log -e err.log my-script.js
[Daemon]
The forever process will run as a daemon which will make the target process start
in the background. This is extremely useful for remote starting simple node.js scripts
without using nohup. It is recommended to run start with -o -l, & -e.
ex. forever start -l forever.log -o out.log -e err.log my-daemon.js
forever stop my-daemon.js
There are several examples designed to test the fault tolerance of forever. Here's a simple usage example:
$ forever -m 5 examples/error-on-timer.js
In addition to passing forever the path to a script (along with accompanying options, described above), you may also pass forever the path to a JSON file containing these options. For example, consider an application with the following file structure:
.
├── forever
│ └── development.json
└── index.js
// forever/development.json
{
// Comments are supported
"uid": "app",
"append": true,
"watch": true,
"script": "index.js",
"sourceDir": "/home/myuser/app",
"logFile": "/home/myuser/logs/forever.log",
"outFile": "/home/myuser/logs/out.log",
"errFile": "/home/myuser/logs/error.log"
}
This application could be started with forever, as shown below:
$ forever start ./forever/development.json
Absolute paths to such configuration files are also supported:
$ forever start /home/myuser/app/forever/development.json
Note: Forever parses JSON configuration files using shush, allowing the use of in-line comments within such files.
JSON configuration files can also be used to define the startup options for multiple applications, as shown below.
[
{
// App1
"uid": "app1",
"append": true,
"watch": true,
"script": "index.js",
"sourceDir": "/home/myuser/app1"
},
{
// App2
"uid": "app2",
"append": true,
"watch": true,
"script": "index.js",
"sourceDir": "/home/myuser/app2",
"args": ["--port", "8081"]
}
]
The forever module exposes some useful methods to use in your code. Each method returns an instance of an EventEmitter which emits when complete. See the forever cli commands for sample usage.
Remark: As of forever@0.6.0 processes will not automatically be available in forever.list(). In order to get your processes into forever.list() or forever list you must instantiate the forever socket server:
forever.startServer(child);
This method takes multiple forever.Monitor instances which are defined in the forever-monitor dependency.
Synchronously sets the specified configuration (config) for the forever module. There are two important options:
| Option | Description | Default |
|---|---|---|
| root | Directory to put all default forever log files | forever.root |
| pidPath | Directory to put all forever *.pid files | [root]/pids |
| sockPath | Directory for sockets for IPC between workers | [root]/sock |
| loglength | Number of logs to return in forever tail | 100 |
| columns | Array of columns to display when format is true | forever.config.get('columns') |
| debug | Boolean value indicating to run in debug mode | false |
| stream | Boolean value indicating if logs will be streamed | false |
Starts a script with forever. The options object is what is expected by the Monitor of forever-monitor.
Starts a script with forever as a daemon. WARNING: Will daemonize the current process. The options object is what is expected by the Monitor of forever-monitor.
Stops the forever daemon script at the specified index. These indices are the same as those returned by forever.list(). This method returns an EventEmitter that raises the 'stop' event when complete.
Stops all forever scripts currently running. This method returns an EventEmitter that raises the 'stopAll' event when complete.
The format parameter is a boolean value indicating whether the returned values should be formatted according to the configured columns which can set with forever columns or programmatically forever.config.set('columns').
Returns a list of metadata objects about each process that is being run using forever. This method will return the list of metadata as such. Only processes which have invoked forever.startServer() will be available from forever.list()
The format parameter is a boolean value indicating whether the returned values should be formatted according to the configured columns which can set with forever columns or programmatically forever.config.set('columns').
Responds with the logs from the target script(s) from tail. There are two options:
length (numeric): is is used as the -n parameter to tail.stream (boolean): is is used as the -f parameter to tail.Cleans up any extraneous forever *.pid files that are on the target system. This method returns an EventEmitter that raises the 'cleanUp' event when complete.
Removes all log files from the root forever directory that do not belong to current running forever processes. Processes are the value returned from Monitor.data in forever-monitor.
Starts the forever HTTP server for communication with the forever CLI. NOTE: This will change your process.title. This method takes multiple forever.Monitor instances which are defined in the forever-monitor dependency.
By default forever places all of the files it needs into /$HOME/.forever. If you would like to change that location just set the FOREVER_ROOT environment variable when you are running forever:
FOREVER_ROOT=/etc/forever forever start index.js
Make sure that the user running the process has the appropriate privileges to read & write to this directory.
$ npm test