forever vs nodemon vs pm2 vs supervisor
Node.js 应用进程管理与开发重启工具深度对比
forevernodemonpm2supervisor

Node.js 应用进程管理与开发重启工具深度对比

forevernodemonpm2supervisor 都是用于管理 Node.js 进程生命周期的工具,但它们的定位截然不同。nodemon 专为开发环境设计,通过监听文件变化自动重启服务以提升开发效率;pm2 是生产级进程管理器,提供集群模式、日志管理和进程守护;forever 是早期的保活工具,功能较为基础;supervisor 已停止维护,属于历史遗留方案。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
forever013,865150 kB342-MIT
nodemon026,694219 kB916 天前MIT
pm2042,974838 kB1,0903 个月前AGPL-3.0
supervisor03,738-539 年前MIT

Node.js 进程管理工具:forever vs nodemon vs pm2 vs supervisor

在 Node.js 生态中,保持服务持续运行和在开发时自动重启是两个核心需求。forevernodemonpm2supervisor 都试图解决这个问题,但它们的架构设计和适用场景有显著差异。作为架构师,我们需要根据环境(开发 vs 生产)和功能需求(保活 vs 集群)来做出选择。

🚀 核心定位:开发辅助 vs 生产守护

这四个工具可以分为两类:开发工具和生产工具。

nodemon 纯粹为开发体验设计。

  • 它监听文件系统的变化。
  • 一旦检测到代码修改,立即杀死旧进程并启动新进程。
  • 不适合生产环境,因为它没有进程守护的高级容错机制。
# nodemon: 启动开发服务器
npx nodemon app.js

pm2 是生产级进程管理器。

  • 它守护进程,崩溃后自动重启。
  • 支持集群模式(Cluster Mode),利用多核 CPU。
  • 提供日志轮转和监控。
# pm2: 启动生产进程
pm2 start app.js --name "my-app" -i max

forever 是早期的保活工具。

  • 主要功能是确保脚本在退出时重新启动。
  • 功能相对单一,缺乏现代管理特性。
# forever: 启动脚本保活
forever start app.js

supervisor 是历史遗留工具。

  • 早期用于开发环境自动重启。
  • 目前已不再维护,功能被 nodemon 取代。
# supervisor: 启动(已不推荐)
supervisor app.js

🔄 重启机制:文件监听 vs 崩溃恢复

理解它们何时重启进程至关重要。

nodemon 基于文件变更触发重启。

  • 你需要配置忽略哪些文件(如 node_modules)。
  • 适合代码频繁变动的开发阶段。
// nodemon.json 配置示例
{
  "watch": ["src"],
  "ext": "ts,json", 
  "ignore": ["src/tests"],
  "exec": "ts-node ./index.ts"
}

pm2 基于进程状态触发重启。

  • 当进程退出码非 0 或内存超限时重启。
  • 也可以配置文件监听(--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 可以实现简单的零停机部署。

遗留系统: 如果遇到 foreversupervisor,制定迁移计划。supervisor 应优先替换为 nodemonforever 应逐步迁移至 pm2 以获得更好的可观测性。

📊 总结对比表

特性nodemonpm2foreversupervisor
主要场景开发生产 + 开发生产 (旧)开发 (旧)
文件监听✅ 原生支持✅ 可选 (--watch)❌ 不支持✅ 原生支持
崩溃重启✅ (视为文件变动)✅ 核心功能✅ 核心功能✅ (视为文件变动)
集群模式✅ 支持
日志管理❌ (输出到 stdout)✅ 高级管理⚠️ 基础重定向⚠️ 基础重定向
维护状态✅ 活跃✅ 活跃⚠️ 缓慢❌ 停止

🎯 最终结论

在现代 Node.js 架构中,nodemon + pm2 是标准组合。开发时用 nodemon 享受热重载,部署时用 pm2 确保稳定运行。foreversupervisor 属于上一代工具链,除非维护旧系统,否则不应出现在新项目的依赖列表中。

如何选择: forever vs nodemon vs pm2 vs supervisor

  • forever:

    选择 forever 仅用于维护旧项目或极其简单的脚本保活。在新项目中不推荐使用,因为它的功能集不如 pm2 丰富,且社区活跃度较低。如果你的服务器环境非常受限且只需最基础的“挂了重启”,它仍可用。

  • nodemon:

    选择 nodemon 用于本地开发环境。当你需要修改代码后自动重启 Node.js 服务,且不需要生产级的高可用或集群功能时,它是最佳选择。它配置简单,社区支持好,是前端开发者的标准开发工具。

  • pm2:

    选择 pm2 用于生产环境部署。当你需要确保应用崩溃后自动重启、利用多核 CPU 运行集群模式、或需要统一的日志管理和监控仪表盘时,pm2 是行业标准。它也支持开发模式,但主要优势在生产。

  • supervisor:

    不建议在任何新项目中选择 supervisor。该包已长期停止维护,存在未修复的安全隐患和兼容性问题。应迁移至 nodemon(开发)或 pm2(生产)以获得更好的支持和功能。

forever的README

forever

Join the chat at https://gitter.im/foreverjs/forever

Version npmnpm DownloadsBuild StatusDependenciesInline docs

NPM

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

Installation

  $ [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

Usage

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.

Command Line Usage

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

JSON Configuration Files

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.

Multi-App Configuration 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"]
  }
]

Using In Your Code

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.

forever.load (config)

Synchronously sets the specified configuration (config) for the forever module. There are two important options:

OptionDescription  Default
rootDirectory to put all default forever log filesforever.root
pidPathDirectory to put all forever *.pid files[root]/pids
sockPathDirectory for sockets for IPC between workers[root]/sock
loglengthNumber of logs to return in forever tail100
columnsArray of columns to display when format is trueforever.config.get('columns')
debugBoolean value indicating to run in debug modefalse
streamBoolean value indicating if logs will be streamedfalse

forever.start (file, options)

Starts a script with forever. The options object is what is expected by the Monitor of forever-monitor.

forever.startDaemon (file, options)

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.

forever.stop (index)

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.

forever.stopAll (format)

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').

forever.list (format, callback)

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').

forever.tail (target, options, callback)

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.

forever.cleanUp ()

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.

forever.cleanLogsSync (processes)

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.

forever.startServer (monitor0, monitor1, ..., monitorN)

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.

Logging and output file locations

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.

Run Tests

  $ npm test

License: MIT

Author: Charlie Robbins

Maintainer: Igor Savin

Contributors: Fedor Indutny, James Halliday, Charlie McConnell, Maciej Malecki, John Lancaster