Procfile必须命名为Procfile、置于根目录、无扩展名、LF换行;web进程须用预编译二进制或明确路径的go run,监听$PORT环境变量;go.mod需声明Go版本;环境变量须由Go代码用os.Getenv读取。

Procfile 必须叫 Procfile,且放在项目根目录
Heroku 只认这个文件名,大小写敏感,procfile 或 PROCFILE 都无效。它不读 .env、docker-compose.yml 或任何其他配置文件来启动进程。
常见错误是把 Procfile 放在 cmd/ 或 src/ 下,导致部署后提示 No Procfile detected 或直接 fallback 到默认行为(比如尝试运行 npm start)。
- 确保执行
ls -a能看到根目录下有Procfile - 文件无扩展名,不是
Procfile.txt - 用 Unix 换行符(LF),Windows 的 CRLF 可能导致解析失败但不报错
web 进程必须用 go run 或预编译二进制,不能依赖 main.go 路径硬编码
Heroku 要求 web 进程监听 $PORT 环境变量指定的端口,并保持前台运行。Go 应用通常不能直接写 web: go run main.go —— 因为项目结构可能含多个 main 包,或 main.go 不在根目录。
更可靠的做法是先构建二进制,再运行:
-
web: ./myapp(推荐)—— 提前在heroku-buildpack-go构建阶段生成可执行文件 -
web: go run cmd/myapp/main.go(仅调试用)—— 构建慢、内存高,上线环境不建议 - 别写
web: go run .,如果当前目录有多个main包会报错go run: no go files listed
示例 Procfile:
web: ./myapp
Go 构建依赖 GOPATH 和 GOVERSION,但 Heroku 默认不设 GOVERSION
Heroku 使用 heroku-buildpack-go 自动检测 Go 版本,规则是:优先读 go.mod 中的 go 1.x 声明;没声明时用 buildpack 默认版本(可能较旧)。若应用用了 io.ReadAll(Go 1.16+)却没声明,构建会失败并报错 undefined: io.ReadAll。
- 务必在
go.mod第一行写明版本,例如:go 1.21 - 避免手动设置
GOPATH—— Heroku 的 buildpack 已处理好模块模式,设了反而可能干扰 - 如需调试构建过程,加
heroku config:set GO_ENV=dev并查看heroku logs --tail中的-----> Installing go行
环境变量注入和端口监听必须由 Go 代码主动读取,Procfile 不做变量替换
Procfile 本身不解析环境变量,web: ./myapp -port $PORT 这种写法不会展开 $PORT,实际传给程序的是字面量 $PORT 字符串,导致绑定失败。
正确做法是让 Go 代码自己读:
- 用
os.Getenv("PORT")获取端口,默认值设为"8080"(本地开发用) - 不要在
Procfile里拼接命令行参数传端口 - 数据库连接串等敏感配置也必须通过
os.Getenv读,不能硬编码或塞进Procfile
典型监听写法:
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.ListenAndServe(":"+port, handler)
Heroku 对 Go 的支持很直接,但卡点往往藏在路径、版本声明和环境变量使用习惯上——尤其是本地能跑通的命令,一到线上就因 $PORT 未展开或 go.mod 版本缺失而静默失败。










