air-go

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Air — Go Hot Reload

Air — Go 应用热重载

Air watches Go source files and rebuilds/restarts your app on changes. Essential for web server development where you want sub-second feedback.
Air 会监听Go源文件,在文件变更时重新构建/重启你的应用。对于需要亚秒级反馈的Web服务器开发来说,它是必不可少的工具。

Install

安装

bash
go install github.com/air-verse/air@latest
bash
go install github.com/air-verse/air@latest

Basic usage

基础用法

Run
air
in your project root. With no config, it watches
.go
files, rebuilds, and restarts. For anything non-trivial, use a
.air.toml
.
在项目根目录运行
air
命令。无配置情况下,它会监听
.go
文件,进行重新构建并重启应用。对于非简单项目,请使用
.air.toml
配置文件。

.air.toml

.air.toml

toml
root = "."
tmp_dir = "tmp"

[build]
  bin = "./tmp/main"
  cmd = "go build -o ./tmp/main ."
  delay = 500
  exclude_dir = ["tmp", "k8s", "cmd", "node_modules", "vendor"]
  exclude_regex = ["_test\\.go$"]
  include_ext = ["go", "html", "css", "js", "yml", "yaml", "toml"]
  kill_delay = "1s"
  send_interrupt = true
  stop_on_error = true

[misc]
  clean_on_exit = true
toml
root = "."
tmp_dir = "tmp"

[build]
  bin = "./tmp/main"
  cmd = "go build -o ./tmp/main ."
  delay = 500
  exclude_dir = ["tmp", "k8s", "cmd", "node_modules", "vendor"]
  exclude_regex = ["_test\\.go$"]
  include_ext = ["go", "html", "css", "js", "yml", "yaml", "toml"]
  kill_delay = "1s"
  send_interrupt = true
  stop_on_error = true

[misc]
  clean_on_exit = true

Key settings explained

关键配置说明

SettingWhat it doesWhy it matters
delay
Milliseconds to wait after a file change before rebuildingPrevents rapid-fire rebuilds when saving multiple files
kill_delay
Time to wait after killing the old process before starting the new oneCritical for SQLite/file locks — the old process needs time to release resources
send_interrupt
Send SIGINT before SIGKILLAllows graceful shutdown (flush writes, close DB connections)
stop_on_error
Don't restart on build errorsPrevents crash loops when you have a syntax error
include_ext
File extensions to watchAdd
html
,
css
,
js
to reload on frontend changes too
exclude_dir
Directories to ignoreExclude test fixtures, k8s manifests, vendored deps
exclude_regex
File patterns to ignoreSkip test files to avoid rebuilding when only tests change
clean_on_exit
Remove tmp dir on exitPrevents stale binaries from confusing the next run
配置项功能说明重要性
delay
文件变更后等待重新构建的毫秒数避免保存多个文件时触发频繁的重新构建
kill_delay
终止旧进程后等待启动新进程的时间对SQLite/文件锁至关重要——旧进程需要时间释放资源
send_interrupt
在发送SIGKILL前先发送SIGINT允许优雅关闭(刷新写入、关闭数据库连接)
stop_on_error
构建出错时不再重启应用避免出现语法错误时陷入崩溃循环
include_ext
要监听的文件扩展名添加
html
css
js
以在前端变更时也触发重载
exclude_dir
要忽略的目录排除测试 fixtures、k8s清单、第三方依赖包
exclude_regex
要忽略的文件模式跳过测试文件,避免仅测试文件变更时触发重新构建
clean_on_exit
退出时删除临时目录防止陈旧二进制文件干扰下次运行

Makefile integration

与Makefile集成

makefile
.PHONY: dev dev-email dev-clean
makefile
.PHONY: dev dev-email dev-clean

Dev: console output, fresh state

Dev: 控制台输出,全新状态

dev: dev-clean air
dev: dev-clean air

Dev: real emails, LAN-accessible for mobile testing

Dev: 发送真实邮件,支持LAN访问用于移动端测试

dev-email: dev-clean $(call setup_env, .env.prod) SMTP_HOST=smtp.example.com
BASE_URL=http://$(LAN_IP):8080
air
dev-clean: @rm -f app.db app.db-shm app.db-wal tmp/main @-lsof -ti :8080 | xargs kill -9 2>/dev/null || true

The `dev-clean` target is important — it kills anything on the port and removes
stale DB files before starting fresh.
dev-email: dev-clean $(call setup_env, .env.prod) SMTP_HOST=smtp.example.com
BASE_URL=http://$(LAN_IP):8080
air
dev-clean: @rm -f app.db app.db-shm app.db-wal tmp/main @-lsof -ti :8080 | xargs kill -9 2>/dev/null || true

`dev-clean`目标非常重要——它会杀死端口上的所有进程,并在重新启动前删除陈旧的数据库文件。

Passing environment variables

传递环境变量

Air inherits the parent shell's environment. Set env vars inline before
air
:
bash
undefined
Air会继承父shell的环境变量。在
air
命令前直接设置环境变量:
bash
undefined

Inline

直接设置

PORT=3000 DEBUG=true air
PORT=3000 DEBUG=true air

From .env file in Makefile

在Makefile中从.env文件读取

$(call setup_env, .env.dev) air

Do NOT put env vars in `.air.toml` — it doesn't support that. Environment is
always from the shell.
$(call setup_env, .env.dev) air

不要将环境变量放在`.air.toml`中——它不支持这种方式。环境变量始终来自shell。

Common issues and fixes

常见问题与解决方法

"address already in use"

「地址已被占用」

The previous process didn't die. Fix:
bash
lsof -ti :8080 | xargs kill -9
Or add to
dev-clean
target as shown above.
之前的进程未终止。解决方法:
bash
lsof -ti :8080 | xargs kill -9
或者如上文所示,将该命令添加到
dev-clean
目标中。

"database is locked" (SQLite)

「数据库已锁定」(SQLite)

Air kills the old process and starts the new one, but SQLite WAL files can linger. Fix with these
.air.toml
settings:
toml
[build]
  kill_delay = "1s"          # Give old process time to release the lock
  send_interrupt = true      # Graceful shutdown via SIGINT
  pre_cmd = ["rm -f app.db-shm app.db-wal"]  # Clean stale lock files
If using an in-memory DB or ephemeral dev DB, just delete it on each rebuild:
toml
[build]
  pre_cmd = ["rm -f app.db app.db-shm app.db-wal"]
Air会终止旧进程并启动新进程,但SQLite的WAL文件可能会残留。通过以下
.air.toml
配置解决:
toml
[build]
  kill_delay = "1s"          # 给旧进程时间释放锁
  send_interrupt = true      # 通过SIGINT实现优雅关闭
  pre_cmd = ["rm -f app.db-shm app.db-wal"]  # 清理陈旧锁文件
如果使用内存数据库或临时开发数据库,只需在每次重新构建时删除它:
toml
[build]
  pre_cmd = ["rm -f app.db app.db-shm app.db-wal"]

"too many open files" on large projects

大型项目中出现「打开文件过多」

Air's file watcher can hit OS limits. Exclude unnecessary directories:
toml
[build]
  exclude_dir = ["tmp", "vendor", "node_modules", ".git", "k8s", "docs"]
Air的文件监视器可能会达到操作系统限制。排除不必要的目录:
toml
[build]
  exclude_dir = ["tmp", "vendor", "node_modules", ".git", "k8s", "docs"]

Air exits immediately in background/CI

在后台/CI中Air立即退出

Air is a foreground tool — it watches stdin for
Ctrl+C
. In scripts or CI, use
go run .
instead. Air is for interactive development only.
Air是一个前台工具——它会监听标准输入以等待
Ctrl+C
。在脚本或CI中,请改用
go run .
。Air仅适用于交互式开发。

Changes not detected

未检测到变更

Check that your file extension is in
include_ext
and the directory isn't in
exclude_dir
. Air only watches extensions you explicitly list.
检查你的文件扩展名是否在
include_ext
中,且所在目录未被列入
exclude_dir
。Air仅会监听你明确列出的扩展名。

Watching non-Go files

监听非Go文件

To rebuild on HTML/CSS/JS changes (useful for apps that serve static files):
toml
[build]
  include_ext = ["go", "html", "css", "js"]
Air will rebuild the Go binary even when only frontend files change. This is fine — Go builds are fast and the restart picks up the new static files.
要在HTML/CSS/JS变更时触发重新构建(适用于提供静态文件的应用):
toml
[build]
  include_ext = ["go", "html", "css", "js"]
即使只有前端文件变更,Air也会重新构建Go二进制文件。这没问题——Go构建速度很快,重启后会加载新的静态文件。

Multi-binary projects

多二进制文件项目

If your project has multiple binaries (
cmd/server
,
cmd/worker
), point
cmd
at the one you want:
toml
[build]
  cmd = "go build -o ./tmp/server ./cmd/server"
  bin = "./tmp/server"
Run a second air instance in another terminal for the worker if needed, with a separate config:
bash
air -c .air.worker.toml
如果你的项目有多个二进制文件(如
cmd/server
cmd/worker
),将
cmd
指向你需要的那个:
toml
[build]
  cmd = "go build -o ./tmp/server ./cmd/server"
  bin = "./tmp/server"
如果需要,在另一个终端中运行第二个Air实例来处理worker,使用单独的配置:
bash
air -c .air.worker.toml