cmd / procman

procman is a process manager for local development on macOS.

It is open source.

Install:

go install github.com/croaky/procman@main

Define processes in Procfile.dev. For example:

clock: bundle exec ruby cmd/clock.rb
esbuild: ./bin/build-js --watch
queues: bundle exec ruby cmd/queues.rb
web: bundle exec ruby cmd/web.rb

Run processes by name, comma-delimited:

procman esbuild,web

There are no options or flags.

procman multiplexes process output:

esbuild | bundling js/app.ts, css/app.css
esbuild | watching...
web     | Listening on http://0.0.0.0:3000

procman runs until it receives SIGINT (Ctrl+C), SIGTERM, or SIGHUP. When one process exits, procman sends SIGINT to the others, waits 5 seconds, and sends SIGKILL to any process that remains. It runs one process per definition and does not load .env.

File watching

Add # watch: PATTERNS to restart a process when files change:

clock: bundle exec ruby cmd/clock.rb    # watch: lib/**/*.rb
esbuild: ./bin/build-js --watch
queues: bundle exec ruby cmd/queues.rb  # watch: lib/**/*.rb
web: bundle exec ruby cmd/web.rb        # watch: lib/**/*.rb,ui/views/**/*.haml

Patterns are relative to the directory containing Procfile.dev. Globs support * (single directory) and ** (recursive). Separate patterns with commas. procman ignores paths in .gitignore, so build output does not consume watch descriptors.

On file changes, procman sends SIGINT, waits for exit, and restarts the process. It debounces changes with a 100ms window and serializes restarts per process.

Kill a process on a port

When a process outlives procman and holds its port, a script on $PATH clears it:

kill-pid-on-port 3000
#!/bin/bash

set -euo pipefail

lsof -n -i :"$1" | grep LISTEN | awk '{ print $2 }' | xargs kill

lsof -ti :3000 | xargs kill is shorter, but -ti returns every process on the port, clients included. grep LISTEN limits it to the server.

← All articles