Procfile guide: syntax, process types, and running it locally
A Procfile is a plain text file named Procfile in the root of your project. Each line names a process and gives the command that starts it, written as name: command. Heroku defined the format. Local runners such as Foreman, Honcho, Overmind, and Rig read the same file, as does the Heroku CLI, so one list of commands can start a web server, a worker, and a scheduler together. This guide covers the syntax, what the special names mean, a complete file for a three-process app, how each runner treats it, and the mistakes that make a line quietly disappear.
What a Procfile is
A Procfile declares the processes that make up an app. It does not install dependencies, build assets, or choose a language runtime. It only says what to run.
Heroku reads the file to decide what each dyno runs. On your own machine, a Procfile runner reads the same file and starts each command as a process. The format is a convention, not a standard. Heroku defines it, and every other tool decides what to accept, so check the manual of the runner you use. The name rules below are one example: Heroku lists hyphens in a process type, and Foreman’s manual does not. The Procfile glossary entry has the short definition.
Syntax
Each line has one shape:
<process type>: <command>The rules that matter in practice:
- File name. Heroku requires the file to be named exactly
Procfile, with no extension, in the root directory of the app. Its article saysProcfile.txtis not valid. Rig also looks only forProcfilein the project root, so a name such asProcfile.devis not read. - One process per line. A line is a process type, a colon, and a command. Write the command as you would type it in a shell.
- Process type names. Heroku lists alphanumerics, hyphens, and underscores. Rig accepts letters, digits, hyphens, and underscores. Foreman’s manual lists letters, numbers, and the underscore only, so use underscores if you want to stay within what it documents.
- Comments. Rig skips blank lines and lines that start with
#. Check your own runner’s manual before you rely on comments there, and keep notes in a README if the file also deploys to Heroku. - Long commands. Rig does not support continuation lines, so each command stays on one line. Move a long command into a script file and call that.
Process types: web, worker, and release
The name before the colon is a label, and only two labels carry meaning on Heroku.
| Process type | What it means on Heroku | What to know locally |
|---|---|---|
web | The only type that receives HTTP traffic from Heroku’s routers. Its command must bind to the port in PORT. | Nothing on your machine routes traffic by process type, so any process can serve HTTP. The name does not choose its port. |
worker | No special meaning. The usual name for background jobs, such as a queue consumer. | An ordinary process. Name it for what it does. |
release | Runs in the release phase, before a new release is deployed. If it fails, the release is not deployed. | heroku local does not run it, so run migrations yourself when you work locally. |
| Anything else | A free label, such as scheduler or clock. | An ordinary process. |
Write a Procfile for web, worker, and scheduler
Take a Node app with an HTTP server, a queue worker, and a scheduler that adds recurring jobs to the queue. The three entry points are src/web.js, src/worker.js, and src/scheduler.js. The Procfile is three lines:
web: node src/web.js
worker: node src/worker.js
scheduler: node src/scheduler.jsThe web process reads its port from the environment and falls back to a default, so it works under a runner that sets PORT and when you start it by hand:
const http = require("node:http");
const port = Number(process.env.PORT) || 3000;
http
.createServer((req, res) => res.end("ok"))
.listen(port, () => console.log(`web listening on ${port}`));Four choices keep a file like this from causing trouble later:
- One program per line. Keep installs, builds, and migrations out of the Procfile. A
webline that runsnpm install && node src/web.jsreinstalls on every start. - Run one scheduler. A simple scheduler like this one enqueues each recurring job once per copy, so two copies enqueue every job twice. Locally you run one of each process type. If you deploy the Procfile to a platform that can run several copies of a type, keep the scheduler at one.
- Keep the scheduler out of the worker. A slow job then cannot delay the next scheduled run.
- Add
releaseonly when you need it. A line such asrelease: node scripts/migrate.jsruns on Heroku before a deploy, andheroku localdoes not run it.
Paste the file into the Procfile validator to see how each line is read. It will note that the web command does not mention $PORT, which is fine here because the code reads process.env.PORT.
Environment variables and PORT
On Heroku, the web process has to bind to the port in PORT. On your machine nothing sets it unless the runner does or you do. Foreman sets it for each process: the value starts at the base port given with -p and rises by 100 for each process line. Rig exports PORT when a port is set for the project. Two habits keep one Procfile working in both places.
- Read
PORTwith a fallback, as in the example above. - Do not hard-code a port in the command.
web: node src/web.js --port 3000pins every checkout of the app to port 3000, so two copies cannot run side by side.
Keep secrets and per-machine settings out of the Procfile. Foreman and Honcho both take -e to name an environment file, and Rig takes environment variables from the project’s active env profile.
Run it locally
Each runner starts from the same file:
# Heroku CLI
heroku local
# Foreman
foreman start
# Honcho (Python)
honcho start
# Overmind (runs each process in tmux)
overmind start- Heroku CLI.
heroku localstarts the process types in your Procfile, andheroku local webstarts one. It does not run thereleasetype. - Foreman.
foreman startruns one instance of each process type,foreman start webruns only that type, andforeman start -f Procfile.devreads a differently named file. - Honcho. A Python port of Foreman.
honcho startruns the file, andhoncho -f Procfile.dev startreads another one. Its documentation says it is not meant to match Foreman feature for feature, so check the flags you rely on. - Overmind. Runs each process in its own tmux window, so tmux has to be installed.
overmind connect workerattaches to that process, andovermind restart workerrestarts it without touching the others. By default one process dying stops the rest, and-rrestarts the processes you name.
A Procfile only describes processes. Whether a crashed process comes back, and whether one crash stops the rest, is the runner’s decision. Test it once: kill the worker and watch what happens to the web process. For a wider comparison with tmux, concurrently, and Docker Compose, read run multiple dev servers locally.
Common mistakes
- Wrong file name.
Procfile.devandProcfile.txtare notProcfile. Rig does not read them. Foreman and Honcho can read another name through-f, but Heroku requiresProcfile. - A space before the colon.
web : node src/web.jsdoes not match Rig’s pattern, because the name must be followed directly by the colon. Rig does not list that line as a script. - A dot or space in the name.
mailer.previewfails the same pattern, and it is outside the characters Heroku lists. Usemailer-preview, ormailer_previewif you use Foreman. - A port hard-coded in
web. The command ignores thePORTthat the runner or platform sets. - Setup work in the command. Installs and builds belong in a setup step, not in a line that runs on every start.
- Expecting
releaseto run locally.heroku localskips it, so a migration that works on Heroku may never have run on your machine.
What Rig does with a Procfile
Rig reads a Procfile in the project root. This is everything it does with the file:
- It looks for a file called
Procfilein the project root. Names such asProcfile.devare not read. - It accepts a line only when it matches
^([A-Za-z0-9_-]+):\s*(.+)$. It skips blank lines and lines that start with#, and it has no continuation lines. - It turns each process type into a script you can select. It marks a script as recommended when it looks like a server.
- It runs the command with
/bin/sh -c, or withcmd.exe /d /s /con Windows. - When a port is set for the project, it appends
--port Nto the command and exportsPORT,VITE_PORT,HOST_PORT, andnpm_config_port. - It takes environment variables from the project’s active env profile.
- It lets extra scripts run alongside the selected one.
For the example file, Rig lists web, worker, and scheduler as three scripts. With port 4000 set on the project and web selected, Rig runs node src/web.js --port 4000 with PORT=4000 in the environment. The server above reads PORT, so the extra argument is ignored.
The flag goes on the end of the line
Rig appends --port N to the whole command line, and a command that does not accept --port still receives it. In a chain such as npm run build && node src/web.js, the flag attaches to the last command only. Keep a Procfile command to one program, or put the program that should receive the flag last.
One selected script, plus extras
Rig treats each process type as a script you select, and runs extra scripts alongside the selected one. Foreman’s foreman start runs one instance of every process type in one command, so check how your project is set up before you assume all three processes start together. See Procfile projects for the settings, and Procfile plus sidecars for how a Procfile and sidecar processes sit on one board.
Frequently asked questions
What is a Procfile?
A plain text file named Procfile that lists an app’s processes, one per line, as a process type, a colon, and a command. Heroku uses it to decide what each dyno runs. Runners such as Foreman, Honcho, Overmind, and Rig read the same format to start the processes on your machine.
Does a Procfile need a web process?
Only if the app serves HTTP traffic on Heroku. The web type is the only one that receives traffic from Heroku’s routers, and its command must bind to the port in PORT. A process that receives no HTTP traffic can use any other name.
How do I run a Procfile locally?
Use a Procfile runner. heroku local runs the file through the Heroku CLI, foreman start and honcho start use Foreman and Honcho, and overmind start runs each process in its own tmux window. Rig lists each process type as a script you can start from the app.
What does the release process type do, and does it run locally?
On Heroku, the release command runs in the release phase, before a new release is deployed, and a failure stops the release. heroku local does not run it. Run your migration command by hand, or from another script, when you work locally.
Can I name the file something other than Procfile?
Heroku requires the exact name Procfile. Foreman and Honcho accept another file name through -f. Rig looks for a file called Procfile in the project root, so a file such as Procfile.dev is not picked up.
How does Rig run a Procfile?
Rig turns each process type into a selectable script and runs the command with /bin/sh -c, or with cmd.exe on Windows. If the project has a port set, it appends --port N to the command and exports PORT, VITE_PORT, HOST_PORT, and npm_config_port.
Sources
- Heroku Dev Center: The Procfile
- Heroku Dev Center: Release Phase
- Heroku Dev Center: Running Apps Locally
- Heroku Changelog: Heroku local no longer runs the release process type
- foreman(1): manage Procfile-based applications
- Honcho: manage Procfile-based applications
- Honcho: Using Procfiles
- Overmind: process manager for Procfile-based applications and tmux
- Overmind source: start/command.go, tmux check
- Rig documentation: Procfile projects (parser and runner behaviour confirmed in Rig’s source code)
Run your whole stack from one window
Rig is a Mac app that starts, stops, and watches the processes in your project, with logs and ports in one place. Local use is free, and your source code stays on your Mac.