File: README.md
:cloud: Air - Live reload for Go apps
Air is a live-reloading command line utility for developing Go applications. Run air in your project root directory, leave it alone, and focus on your code. Note that this tool has nothing to do with hot-deploy for production.
Contents
- Air - Live reload for Go apps
Installation
Via `go install` (recommended)
With go 1.25 or higher:
go install github.com/air-verse/air@latestMake sure your Go bin directory is in your PATH:
export PATH="$PATH:$(go env GOPATH)/bin"Via `go get -tool` (project install)
With go 1.25 or higher:
go get -tool github.com/air-verse/air@latest
# then use it like so:
go tool air -vVia install.sh
# binary will be $(go env GOPATH)/bin/air
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# or install it into ./bin/
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s
air -vVia goblin.run
See goblin.run.
# binary will be /usr/local/bin/air
curl -sSfL https://goblin.run/github.com/air-verse/air | sh
# to put to a custom path
curl -sSfL https://goblin.run/github.com/air-verse/air | PREFIX=/tmp shVia Homebrew
brew install go-airVia Scoop
scoop install airVia mise
mise use -g airVia Docker/Podman
Pull the cosmtrek/air image and see Docker for usage.
Quick start
# enter your project
cd /path/to/your_project
# first tries `.air.toml` in the current directory; if not found, uses defaults
airTo generate a config file you can edit, run air init once and then air from then on:
# writes .air.toml with the default settings
air init
# picks up .air.toml automatically
airTo use a specific config file explicitly, pass -c:
air -c .air.tomlFor every available option refer to the air_example.toml file.
Features
- Colorful log output
- Customize build or any command
- Support excluding subdirectories
- Allow watching new directories after Air started
- Better building process
- Configurable
.envfile loading
Usage
Runtime arguments
You can pass arguments for running the built binary by adding them after the air command.
# Will run ./tmp/main bench
air bench
# Will run ./tmp/main server --port 8080
air server --port 8080You can separate the arguments passed for the air command and the built binary with the -- argument.
# Will run ./tmp/main -h
air -- -h
# Will run air with custom config and pass -h argument to the built binary
air -c .air.toml -- -hDebug
air -d prints all logs.
Configuration
Overwrite specific configuration from arguments
Air config fields are supported as command-line arguments. You can view the available arguments by running:
air -h
# or
air --helpIf you want to configure the build command and run command, you can use the following command without a config file:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api"Use a comma to separate items for arguments that take a list as input:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api" --build.exclude_dir "templates,build"List arguments can also be repeated, and the values are appended in the order they appear. This is handy when the command line is generated by a script or Makefile:
# equivalent to --env_files ".env,.env.local,.env.secret"
air --env_files ".env,.env.local" --env_files ".env.secret"Startup banner
Use misc.startup_banner to control what Air prints at startup.
[misc]
# Not set (default): show built-in ASCII banner with version.
# Set to empty string: print nothing.
startup_banner = ""
# Set to custom text: print this text instead of the built-in banner.
# startup_banner = "API watcher"Entrypoint
Use build.entrypoint to point at the binary generated by build.cmd and describe how it should be executed. The value can be either a string (just the executable) or an array of strings. When using an array, the first element is the executable (resolved relative to root unless it lacks a path separator, in which case $PATH is consulted) and every subsequent element is treated as a default argument. Values from build.args_bin and the command line are appended after the inline arguments. The legacy build.bin field is deprecated and will be removed in a future release, so prefer the entrypoint form going forward.
[build]
entrypoint = ["./tmp/main"]
args_bin = ["server", ":8080"]
# Inline the default arguments directly after the binary.
entrypoint = ["./tmp/main", "server", ":8080"]
# Use PATH-resolved tools like dlv by omitting path separators.
entrypoint = [
"dlv", "exec", "--accept-multiclient", "--log", "--headless", "--continue",
"--listen=:8999", "--api-version", "2", "./tmp/main",
]Environment files
Air can automatically load environment variables from .env files before both building and running when env_files is configured.
# Loads .env.development and then .env files.
# Values in the lattermost file overwrite any preceding ones.
# Does not overwrite variables that were present before running air.
env_files = [".env.development", ".env"]Platform-specific build overrides
You can override build settings per OS with [build.windows], [build.darwin], and [build.linux]. These blocks override the base [build] values when running on the matching platform. Only the following fields are supported in platform blocks: pre_cmd, cmd, post_cmd, bin, entrypoint, full_bin, args_bin.
[build]
cmd = "go build -o ./tmp/main ."
bin = "./tmp/main"
[build.windows]
cmd = "go build -o ./tmp/main.exe ."
bin = "tmp\\main.exe"
entrypoint = ["tmp\\main.exe"]Running air init adds a platform block for the current OS when its defaults differ from the base configuration.
Watch rules: run a command instead of rebuilding
Sometimes a change should run a command rather than rebuild your app — frontend assets served from disk, templ/sqlc/go generate pipelines, and so on. Declare a [[build.rules]] block for each of them:
[build]
cmd = "go build -o ./tmp/main ."
# the main build ignores the frontend...
exclude_dir = ["web"]
# ...but this rule watches it and rebuilds the assets on change
[[build.rules]]
name = "assets"
include_dir = ["web"]
include_ext = ["js", "ts", "css"]
cmd = "npm run build"
[[build.rules]]
name = "templ"
include_ext = ["templ"]
cmd = "templ generate"A file matched by a rule runs the rule's cmd and never triggers a rebuild, even if it would also match the main build's watch settings. Rule directories are watched even when listed in exclude_dir. If a rule's command generates files the main build watches (for example, templ generate writing .go files), the rebuild follows naturally.
Each rule supports include_dir, include_ext, include_file, exclude_regex, and a delay (debounce in milliseconds, default 1000). At least one of the include_* matchers is required. Rules run their commands to completion; changes arriving meanwhile queue a follow-up run.
Proxy: reload the browser automatically
Air can put a small proxy in front of your web app that refreshes the browser after every successful rebuild, so you no longer have to hit reload yourself.
[proxy]
enabled = true
# the port you open in the browser
proxy_port = 8090
# the port your app listens on
app_port = 8080Start air as usual and open http://localhost:8090 instead of your app's own port. Requests are forwarded to app_port, and Air injects a tiny script before the `` tag of every HTML response; when a rebuild finishes, the script reloads the page.
Two things are required for this to work:
- your HTML must contain a `` tag — there is nowhere to inject the script otherwise, and the page is served unchanged;
- the files you edit must be watched, so static assets need to be covered by
include_dir,include_ext, orinclude_file.
If your app is slow to boot (database connections, config loading) and you see "unable to reach app" errors, give it more time:
[proxy]
# how long to keep retrying the app after a rebuild, in milliseconds (default 5000)
app_start_timeout = 10000Docker
Using the official image
Pull this Docker image: cosmtrek/air.
docker/podman run -it --rm \
-w "" \
-e "air_wd=" \
-v $(pwd): \
-p :<APP SERVER PORT> \
cosmtrek/air \
-c <CONF>`` is your project path in the container, e.g. /go/example. If you want to enter the container, add --entrypoint=bash.
One of my projects runs in Docker:
docker run -it --rm \
-w "/go/src/github.com/cosmtrek/hub" \
-v $(pwd):/go/src/github.com/cosmtrek/hub \
-p 9090:9090 \
cosmtrek/airShell function
If you want to use air continuously like a normal app, create a function in your ${SHELL}rc (Bash, Zsh, etc…):
air() {
podman/docker run -it --rm \
-w "$PWD" -v "$PWD":"$PWD" \
-p "$AIR_PORT":"$AIR_PORT" \
docker.io/cosmtrek/air "$@"
}$PWD is replaced with the current directory, $AIR_PORT is the port to publish, and $@ accepts arguments of the application itself, for example -c:
cd /go/src/github.com/cosmtrek/hub
AIR_PORT=8080 air -c "config.toml"Docker Compose
services:
my-project-with-air:
image: cosmtrek/air
# working_dir value has to be the same of mapped volume
working_dir: /project-package
ports:
- <any>:<any>
environment:
- ENV_A=${ENV_A}
- ENV_B=${ENV_B}
- ENV_C=${ENV_C}
volumes:
- ./project-relative-path/:/project-package/Without the air image
Dockerfile
# Choose whatever you want, version >= 1.25
FROM golang:1.25-alpine
WORKDIR /app
RUN go install github.com/air-verse/air@latest
COPY go.mod go.sum ./
RUN go mod download
CMD ["air", "-c", ".air.toml"]docker-compose.yaml
version: "3.8"
services:
web:
build:
context: .
# Correct the path to your Dockerfile
dockerfile: Dockerfile
ports:
- 8080:3000
# Important to bind/mount your codebase dir to /app dir for live reload
volumes:
- ./:/appQ&A
command not found: air
Also reported as "No such file or directory". Make sure the Go bin directory is on your PATH:
export GOPATH=$HOME/xxxxx
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:$(go env GOPATH)/bin #Confirm this line in your .profile and make sure to source the .profile if you add it!!!Error under WSL when the bin path contains a single quote
Use \ to escape the ' in the bin. Related issue: #305
How to do hot compile only and not run anything?
See #365.
[build]
cmd = "/usr/bin/true"How to reload the browser automatically on static file changes?
Enable the proxy — see Proxy: reload the browser automatically. Make sure your static files are covered by include_dir, include_ext, or include_file, otherwise editing them never triggers a reload. Refer to issue #512 for additional details.
Development
Please note that it requires Go 1.25+ (see go.mod).
# Fork this project
# Clone it
mkdir -p $GOPATH/src/github.com/cosmtrek
cd $GOPATH/src/github.com/cosmtrek
git clone [email protected]:<YOUR USERNAME>/air.git
# Install dependencies
cd air
make ci
# Explore it and happy hacking!
make installPull requests are welcome.
Release
# Checkout to master
git checkout master
# Add the version that needs to be released
git tag v1.xx.x
# Push to remote
git push origin v1.xx.x
# The CI will process and release a new version. Wait about 5 min, and you can fetch the latest versionMotivation
When I started developing websites in Go and using the gin framework, it was a pity that gin lacked a live-reloading function. So I searched around and tried fresh; it seemed not much flexible, so I intended to rewrite it better. Finally, Air's born.
In addition, great thanks to pilu, no fresh, no air :)
Star History
Sponsor
Give huge thanks to lots of supporters. I've always been remembering your kindness.
License
GNU General Public License v3.0
File: README-ja.md
:cloud: Air - Go アプリケーションのためのライブリロード
Air は Go アプリケーション開発用のライブリロードコマンドラインユーティリティです。プロジェクトのルートディレクトリで air を実行し、放置し、コードに集中してください。なお、このツールは本番環境へのホットデプロイとは無関係です。
目次
インストール
`go install` を使う場合(推奨)
go 1.25 以上が必要です。
go install github.com/air-verse/air@latestGo の bin ディレクトリが PATH に含まれていることを確認してください。
export PATH="$PATH:$(go env GOPATH)/bin"`go get -tool` を使う場合(プロジェクトへのインストール)
go 1.25 以上が必要です。
go get -tool github.com/air-verse/air@latest
# 使い方は以下の通りです:
go tool air -v`install.sh` を使う場合
# バイナリは $(go env GOPATH)/bin/air にインストールされます
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# または./bin/にインストールすることもできます
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s
air -vgoblin.run を使う場合
goblin.run を参照してください。
# バイナリは /usr/local/bin/air にインストールされます
curl -sSfL https://goblin.run/github.com/air-verse/air | sh
# 任意のパスに配置することもできます
curl -sSfL https://goblin.run/github.com/air-verse/air | PREFIX=/tmp shHomebrew を使う場合
brew install go-airScoop を使う場合
scoop install airmise を使う場合
mise use -g airDocker/Podman を使う場合
cosmtrek/air イメージを pull してください。使い方は Docker を参照してください。
クイックスタート
# プロジェクトに移動します
cd /path/to/your_project
# カレントディレクトリの `.air.toml` を優先し、見つからない場合はデフォルト値を使います
air編集可能な設定ファイルが必要な場合は、最初に一度 air init を実行し、それ以降は air を実行するだけです。
# デフォルト設定で .air.toml を生成します
air init
# .air.toml が自動的に読み込まれます
air特定の設定ファイルを明示的に使う場合は -c を指定します。
air -c .air.toml利用可能な設定項目については air_example.toml を参照してください。
特徴
- カラフルなログ出力
- ビルドやその他のコマンドをカスタマイズ
- サブディレクトリを除外することをサポート
- Air 起動後は新しいディレクトリを監視します
- より良いビルドプロセス
- 設定可能な
.envファイルの読み込み
使い方
実行時引数
air コマンドの後に引数を追加することで、ビルドしたバイナリを実行するための引数を渡すことができます。
# ./tmp/main benchを実行します
air bench
# ./tmp/main server --port 8080を実行します
air server --port 8080air コマンドに渡す引数とビルドしたバイナリに渡す引数は -- で区切ることができます。
# ./tmp/main -hを実行します
air -- -h
# カスタム設定で air を実行し、ビルドされたバイナリに -h 引数を渡す
air -c .air.toml -- -hデバッグ
air -dは全てのログを出力します。
設定
引数から指定された設定を上書き
air の設定フィールドはコマンドライン引数としてサポートされています。利用可能な引数は以下のコマンドで確認できます。
air -h
# または
air --helpもしビルドコマンドと起動コマンドを設定したい場合は、設定ファイルを使わずに以下のようにコマンドを使うことができます。
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api"入力値としてリストを取る引数には、アイテムを区切るためにコンマを使用します。
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api" --build.exclude_dir "templates,build"リストを取る引数は繰り返し指定することもでき、値は現れた順に追加されます。コマンドラインをスクリプトや Makefile で生成する場合に便利です。
# --env_files ".env,.env.local,.env.secret" と同じです
air --env_files ".env,.env.local" --env_files ".env.secret"起動バナー
Air が起動時に出力する内容は misc.startup_banner で制御できます。
[misc]
# 未設定(デフォルト): 組み込みの ASCII バナーとバージョンを表示します。
# 空文字列を設定: 何も出力しません。
startup_banner = ""
# 任意のテキストを設定: 組み込みバナーの代わりにこのテキストを出力します。
# startup_banner = "API watcher"Entrypoint
build.entrypoint では、build.cmd が生成したバイナリと、その実行方法を指定します。値は文字列(実行ファイルのみ)でも文字列の配列でも構いません。配列の場合、最初の要素が実行ファイルで(root からの相対パスとして解決されます。パス区切り文字を含まない場合は $PATH から探されます)、それ以降の要素はすべてデフォルト引数として扱われます。build.args_bin とコマンドラインで渡された引数は、これらの引数の後に追加されます。従来の build.bin フィールドは非推奨で、今後のリリースで削除される予定です。entrypoint の書き方を使ってください。
[build]
entrypoint = ["./tmp/main"]
args_bin = ["server", ":8080"]
# デフォルト引数をバイナリの直後にインラインで書くこともできます。
entrypoint = ["./tmp/main", "server", ":8080"]
# パス区切り文字を省くと、dlv のように PATH から解決されます。
entrypoint = [
"dlv", "exec", "--accept-multiclient", "--log", "--headless", "--continue",
"--listen=:8999", "--api-version", "2", "./tmp/main",
]環境変数ファイル
env_files を設定すると、Air はビルド前と実行前に .env ファイルから環境変数を自動的に読み込みます。
# .env.development、続いて .env を読み込みます。
# 後ろのファイルの値が前の値を上書きします。
# air の実行前から存在していた変数は上書きしません。
env_files = [".env.development", ".env"]プラットフォームごとのビルド設定の上書き
[build.windows]、[build.darwin]、[build.linux] を使うと、OS ごとにビルド設定を上書きできます。これらのブロックは、対応するプラットフォームで実行したときに [build] の値を上書きします。プラットフォームブロックでサポートされるのは次のフィールドのみです: pre_cmd、cmd、post_cmd、bin、entrypoint、full_bin、args_bin。
[build]
cmd = "go build -o ./tmp/main ."
bin = "./tmp/main"
[build.windows]
cmd = "go build -o ./tmp/main.exe ."
bin = "tmp\\main.exe"
entrypoint = ["tmp\\main.exe"]現在の OS のデフォルト値が基本設定と異なる場合、air init はその OS 向けのプラットフォームブロックを追加します。
監視ルール: リビルドの代わりにコマンドを実行する
ファイルの変更に対して、アプリのリビルドではなくコマンドを実行したい場合があります。ディスクから配信するフロントエンドのアセットや、templ/sqlc/go generate のようなパイプラインなどです。そうしたものにはそれぞれ [[build.rules]] ブロックを定義します。
[build]
cmd = "go build -o ./tmp/main ."
# メインのビルドはフロントエンドを無視しますが……
exclude_dir = ["web"]
# ……このルールがそれを監視し、変更時にアセットをリビルドします
[[build.rules]]
name = "assets"
include_dir = ["web"]
include_ext = ["js", "ts", "css"]
cmd = "npm run build"
[[build.rules]]
name = "templ"
include_ext = ["templ"]
cmd = "templ generate"ルールに一致したファイルはそのルールの cmd を実行するだけで、メインのビルドの監視条件にも一致する場合であってもリビルドは発生しません。ルールのディレクトリは exclude_dir に含まれていても監視されます。ルールのコマンドがメインのビルドの監視対象となるファイルを生成した場合(たとえば templ generate が .go ファイルを書き出す場合)、リビルドは自然に続いて実行されます。
各ルールは include_dir、include_ext、include_file、exclude_regex、そして delay(デバウンス、ミリ秒単位、デフォルト 1000)をサポートします。include_* のいずれか 1 つは必須です。ルールはコマンドの完了まで待ちます。実行中に届いた変更はキューに入り、完了後にもう一度実行されます。
プロキシ: ブラウザを自動的にリロードする
Air は Web アプリの前段に小さなプロキシを置くことができます。ビルドが成功するたびにブラウザを更新するので、自分でリロードする必要がなくなります。
[proxy]
enabled = true
# ブラウザで開くポート
proxy_port = 8090
# アプリが listen しているポート
app_port = 8080いつも通り air を起動し、アプリ自身のポートではなく http://localhost:8090 をブラウザで開きます。リクエストは app_port に転送され、Air はすべての HTML レスポンスの `` タグの前に小さなスクリプトを注入します。ビルドが完了すると、そのスクリプトがページをリロードします。
これが動作するには 2 つの条件があります。
- HTML に `` タグが含まれていること。含まれていないとスクリプトを注入する場所がなく、ページはそのまま配信されます。
- 編集するファイルが監視対象であること。静的ファイルは
include_dir、include_ext、include_fileのいずれかでカバーする必要があります。
アプリの起動が遅く(データベース接続や設定の読み込みなど)、"unable to reach app" というエラーが出る場合は、待ち時間を延ばしてください。
[proxy]
# ビルド後にアプリへの接続をリトライする時間(ミリ秒、デフォルト 5000)
app_start_timeout = 10000Docker
公式イメージを使う
この Docker イメージを pull してください: cosmtrek/air。
docker/podman run -it --rm \
-w "" \
-e "air_wd=" \
-v $(pwd): \
-p :<APP SERVER PORT> \
cosmtrek/air \
-c <CONF>`` はコンテナ内のプロジェクトのパスです(例: /go/example)。コンテナに入りたい場合は --entrypoint=bash を追加してください。
私のプロジェクトのひとつは Docker で動作しています。
docker run -it --rm \
-w "/go/src/github.com/cosmtrek/hub" \
-v $(pwd):/go/src/github.com/cosmtrek/hub \
-p 9090:9090 \
cosmtrek/airシェル関数
通常のアプリケーションのように air を継続的に使いたい場合は、${SHELL}rc(Bash、Zsh など)に関数を作成できます。
air() {
podman/docker run -it --rm \
-w "$PWD" -v "$PWD":"$PWD" \
-p "$AIR_PORT":"$AIR_PORT" \
docker.io/cosmtrek/air "$@"
}$PWD は現在のディレクトリに置き換えられ、$AIR_PORT は公開するポートを指定し、$@ は -c のようなアプリケーション自体の引数を受け取るためのものです。
cd /go/src/github.com/cosmtrek/hub
AIR_PORT=8080 air -c "config.toml"Docker Compose
services:
my-project-with-air:
image: cosmtrek/air
# working_dir の値はマップされたボリュームの値と同じでなければなりません
working_dir: /project-package
ports:
- <any>:<any>
environment:
- ENV_A=${ENV_A}
- ENV_B=${ENV_B}
- ENV_C=${ENV_C}
volumes:
- ./project-relative-path/:/project-package/air イメージを使わない場合
Dockerfile
# 1.25以上の任意のバージョンを選択してください
FROM golang:1.25-alpine
WORKDIR /app
RUN go install github.com/air-verse/air@latest
COPY go.mod go.sum ./
RUN go mod download
CMD ["air", "-c", ".air.toml"]docker-compose.yaml
version: "3.8"
services:
web:
build:
context: .
# Dockerfile へのパスを正してください
dockerfile: Dockerfile
ports:
- 8080:3000
# ライブリロードのために、コードベースディレクトリを /app ディレクトリにバインド/マウントすることが重要です
volumes:
- ./:/appQ&A
"command not found: air" または "No such file or directory"
Go の bin ディレクトリが PATH に含まれていることを確認してください。
export GOPATH=$HOME/xxxxx
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:$(go env GOPATH)/bin #この設定を .profile で確認し、追加した場合は .profile を source するのを忘れないでください!!!bin のパスに ' が含まれる場合の WSL でのエラー
bin の ' をエスケープするには \ を使用したほうが良いです。関連する issue: #305
ホットコンパイルのみを行い、何も実行しない方法は?
#365 を参照してください。
[build]
cmd = "/usr/bin/true"静的ファイルの変更時にブラウザを自動的にリロードする方法
プロキシを有効にしてください。詳しくはプロキシ: ブラウザを自動的にリロードするを参照してください。静的ファイルが include_dir、include_ext、include_file のいずれかでカバーされていることを確認してください。カバーされていないと、変更してもリロードされません。詳細は issue #512 を参照してください。
開発
必要な Go のバージョンは 1.25+ です(go.mod を参照)。
# プロジェクトをフォークしてください
# クローンしてください
mkdir -p $GOPATH/src/github.com/cosmtrek
cd $GOPATH/src/github.com/cosmtrek
git clone [email protected]:<YOUR USERNAME>/air.git
# 依存関係をインストールしてください
cd air
make ci
# コードを探検してコーディングを楽しんでください!
make installプルリクエストを歓迎します。
リリース
# master にチェックアウトします
git checkout master
# リリースに必要なバージョンタグを付与します
git tag v1.xx.x
# リモートにプッシュします
git push origin v1.xx.x
# CI が実行され、新しいバージョンがリリースされます。約5分待つと最新バージョンを取得できます動機
Go でウェブサイトを開発し始め、gin を使っていた時、gin にはライブリロード機能がないのが残念でした。そこで探し回って fresh を試してみましたが、あまり柔軟ではないようでした。なので、もっと良いものを書くことにしました。そうして、Air が誕生しました。
加えて、pilu に感謝します。fresh がなければ、Air もありませんでした。:)
スターヒストリー
スポンサー
多くの支援者に心から感謝します。皆さんの親切をいつも覚えています。
ライセンス
GNU General Public License v3.0
File: README-zh_cn.md
:cloud: Air - Go 应用的实时重载工具
Air 是为 Go 应用开发设计的实时重载命令行工具。只需在你的项目根目录下输入 air,然后把它放在一边,专注于你的代码即可。注意:该工具与生产环境的热部署无关。
目录
安装
使用 `go install`(推荐)
使用 go 1.25 或更高版本:
go install github.com/air-verse/air@latest请确保你的 Go bin 目录已加入 PATH:
export PATH="$PATH:$(go env GOPATH)/bin"使用 `go get -tool`(安装到项目中)
使用 go 1.25 或更高版本:
go get -tool github.com/air-verse/air@latest
# 然后像这样使用:
go tool air -v使用 install.sh
# 二进制文件会安装到 $(go env GOPATH)/bin/air
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# 或者把它安装在 ./bin/ 路径下
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s
air -v使用 goblin.run
参见 goblin.run。
# 二进制文件将会安装到 /usr/local/bin/air
curl -sSfL https://goblin.run/github.com/air-verse/air | sh
# 自定义路径安装
curl -sSfL https://goblin.run/github.com/air-verse/air | PREFIX=/tmp sh使用 Homebrew
brew install go-air使用 Scoop
scoop install air使用 mise
mise use -g air使用 Docker/Podman
拉取 cosmtrek/air 镜像,用法见 Docker。
快速开始
# 进入你的项目目录
cd /path/to/your_project
# 先尝试读取当前目录中的 `.air.toml`;如果不存在,则使用默认配置
air如果想生成一份可以自行修改的配置文件,先执行一次 air init,之后直接执行 air 即可:
# 生成带有默认配置的 .air.toml
air init
# 会自动读取 .air.toml
air如果要显式指定配置文件,可以使用 -c:
air -c .air.toml全部可用配置项请参考 air_example.toml 文件。
特色
- 彩色的日志输出
- 自定义构建或必要的命令
- 支持排除子目录
- 在 Air 启动之后,允许监听新创建的目录
- 更棒的构建过程
- 可配置的
.env文件加载
使用方法
运行时参数
你可以把参数添加在 air 命令之后,传递给构建出来的二进制文件。
# 会执行 ./tmp/main bench
air bench
# 会执行 ./tmp/main server --port 8080
air server --port 8080你可以使用 -- 参数来分隔传递给 air 命令和传递给二进制文件的参数。
# 会运行 ./tmp/main -h
air -- -h
# 会使用个性化配置来运行 air,并把 -h 传给构建出的二进制文件
air -c .air.toml -- -h调试
air -d 命令能打印所有日志。
配置
使用参数覆盖指定配置
air 的配置字段都支持以命令行参数的形式传入。可以通过下面的命令查看全部可用参数:
air -h
# 或者
air --help如果你只是想配置构建命令和运行命令,可以直接使用以下命令,而无需配置文件:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api"对于以列表形式输入的参数,使用逗号来分隔各项:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api" --build.exclude_dir "templates,build"列表类参数也可以重复传入,取值会按出现顺序依次追加。当命令行由脚本或 Makefile 生成时,这种写法很方便:
# 等价于 --env_files ".env,.env.local,.env.secret"
air --env_files ".env,.env.local" --env_files ".env.secret"启动横幅
使用 misc.startup_banner 控制 Air 启动时打印的内容。
[misc]
# 不设置(默认):显示内置的 ASCII 横幅和版本号。
# 设置为空字符串:什么都不打印。
startup_banner = ""
# 设置为自定义文本:打印这段文本,替代内置横幅。
# startup_banner = "API watcher"Entrypoint
使用 build.entrypoint 指定 build.cmd 构建出的二进制文件,以及它的执行方式。该值可以是字符串(只指定可执行文件),也可以是字符串数组。使用数组时,第一个元素是可执行文件(相对于 root 解析;如果其中不含路径分隔符,则从 $PATH 中查找),其余元素都会作为默认参数。build.args_bin 和命令行传入的参数会追加在这些内联参数之后。旧的 build.bin 字段已弃用,将在未来的版本中移除,请优先使用 entrypoint 的写法。
[build]
entrypoint = ["./tmp/main"]
args_bin = ["server", ":8080"]
# 也可以把默认参数直接内联写在二进制文件后面。
entrypoint = ["./tmp/main", "server", ":8080"]
# 不带路径分隔符时会从 PATH 中查找,例如 dlv。
entrypoint = [
"dlv", "exec", "--accept-multiclient", "--log", "--headless", "--continue",
"--listen=:8999", "--api-version", "2", "./tmp/main",
]环境变量文件
配置 env_files 后,Air 会在构建和运行之前自动从 .env 文件中加载环境变量。
# 依次加载 .env.development 和 .env。
# 靠后文件中的值会覆盖前面的值。
# 不会覆盖运行 air 之前就已存在的变量。
env_files = [".env.development", ".env"]按平台覆盖构建配置
你可以用 [build.windows]、[build.darwin] 和 [build.linux] 按操作系统覆盖构建配置。在对应平台上运行时,这些配置块会覆盖 [build] 中的值。平台配置块中只支持以下字段:pre_cmd、cmd、post_cmd、bin、entrypoint、full_bin、args_bin。
[build]
cmd = "go build -o ./tmp/main ."
bin = "./tmp/main"
[build.windows]
cmd = "go build -o ./tmp/main.exe ."
bin = "tmp\\main.exe"
entrypoint = ["tmp\\main.exe"]当当前系统的默认配置与基础配置不同时,air init 会自动为当前系统生成对应的平台配置块。
监听规则:执行命令而非重新构建
有时候文件变更需要的是执行某个命令,而不是重新构建应用——比如直接从磁盘提供的前端资源,或者 templ/sqlc/go generate 这类流程。可以为它们各自声明一个 [[build.rules]] 配置块:
[build]
cmd = "go build -o ./tmp/main ."
# 主构建流程忽略前端目录……
exclude_dir = ["web"]
# ……但这条规则会监听它,并在变更时重新构建前端资源
[[build.rules]]
name = "assets"
include_dir = ["web"]
include_ext = ["js", "ts", "css"]
cmd = "npm run build"
[[build.rules]]
name = "templ"
include_ext = ["templ"]
cmd = "templ generate"被规则匹配到的文件只会执行该规则的 cmd,绝不会触发重新构建,即使它同时也符合主构建的监听条件。规则涉及的目录即使写在 exclude_dir 里也依然会被监听。如果规则的命令生成了主构建正在监听的文件(例如 templ generate 生成 .go 文件),重新构建自然会随之触发。
每条规则支持 include_dir、include_ext、include_file、exclude_regex 以及 delay(防抖时间,单位毫秒,默认 1000)。include_* 匹配条件至少要填一项。规则会等待命令执行完毕;执行期间到达的变更会排队,结束后再跑一次。
代理:自动刷新浏览器
Air 可以在你的 Web 应用前面挂一个小型代理,每次构建成功后自动刷新浏览器,这样就不用再手动按刷新了。
[proxy]
enabled = true
# 你在浏览器中访问的端口
proxy_port = 8090
# 你的应用实际监听的端口
app_port = 8080照常启动 air,然后在浏览器中访问 http://localhost:8090,而不是应用自己的端口。请求会被转发到 app_port,同时 Air 会在每个 HTML 响应的 `` 标签前注入一小段脚本;构建完成后,这段脚本就会刷新页面。
要让它生效,有两个前提:
- HTML 中必须有 `` 标签——否则没有地方注入脚本,页面会原样返回;
- 你修改的文件必须处于监听范围内,所以静态资源需要被
include_dir、include_ext或include_file覆盖到。
如果你的应用启动较慢(连接数据库、加载配置等),并出现 "unable to reach app" 错误,可以把等待时间调长:
[proxy]
# 构建完成后重试连接应用的时长,单位毫秒(默认 5000)
app_start_timeout = 10000Docker
使用官方镜像
请拉取这个 Docker 镜像:cosmtrek/air。
docker/podman run -it --rm \
-w "" \
-e "air_wd=" \
-v $(pwd): \
-p :<APP SERVER PORT> \
cosmtrek/air \
-c <CONF>`` 是容器中的项目路径,例如 /go/example。如果你想进入容器,请添加 --entrypoint=bash。
我的一个项目运行在 Docker 中:
docker run -it --rm \
-w "/go/src/github.com/cosmtrek/hub" \
-v $(pwd):/go/src/github.com/cosmtrek/hub \
-p 9090:9090 \
cosmtrek/airShell 函数
如果你想像使用普通应用程序那样持续使用 air,可以在你的 ${SHELL}rc(Bash、Zsh 等)中创建一个函数:
air() {
podman/docker run -it --rm \
-w "$PWD" -v "$PWD":"$PWD" \
-p "$AIR_PORT":"$AIR_PORT" \
docker.io/cosmtrek/air "$@"
}其中 $PWD 会被替换为当前目录,$AIR_PORT 是要发布的端口,而 $@ 用于接收应用程序本身的参数,例如 -c:
cd /go/src/github.com/cosmtrek/hub
AIR_PORT=8080 air -c "config.toml"Docker Compose
services:
my-project-with-air:
image: cosmtrek/air
# working_dir 的值必须和挂载的卷保持一致
working_dir: /project-package
ports:
- <any>:<any>
environment:
- ENV_A=${ENV_A}
- ENV_B=${ENV_B}
- ENV_C=${ENV_C}
volumes:
- ./project-relative-path/:/project-package/不使用 air 镜像
Dockerfile
# 选择你想要的版本,>= 1.25
FROM golang:1.25-alpine
WORKDIR /app
RUN go install github.com/air-verse/air@latest
COPY go.mod go.sum ./
RUN go mod download
CMD ["air", "-c", ".air.toml"]docker-compose.yaml
version: "3.8"
services:
web:
build:
context: .
# 修改为你的 Dockerfile 路径
dockerfile: Dockerfile
ports:
- 8080:3000
# 为了实时重载,将代码目录绑定到 /app 目录是很重要的
volumes:
- ./:/appQ&A
遇到 "command not found: air" 怎么办
有时也表现为 "No such file or directory"。请确认 Go bin 目录已加入 PATH:
export GOPATH=$HOME/xxxxx
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:$(go env GOPATH)/bin <---- 请确认这行在您的配置信息中!!!在 WSL 下 bin 路径包含单引号时报错
应该使用 \ 来转义 bin 中的 '。相关 issue:#305
如何只进行热编译而不运行?
参见 #365。
[build]
cmd = "/usr/bin/true"如何在静态文件更改时自动刷新浏览器?
开启代理即可,详见代理:自动刷新浏览器。请确认你的静态文件被 include_dir、include_ext 或 include_file 覆盖到,否则修改它们不会触发刷新。更多细节请参考 #512。
开发
请注意:当前需要 Go 1.25+(见 go.mod)。
# 1. 首先复刻(fork)这个项目
# 2. 其次克隆(clone)它
mkdir -p $GOPATH/src/github.com/cosmtrek
cd $GOPATH/src/github.com/cosmtrek
git clone [email protected]:<YOUR USERNAME>/air.git
# 3. 安装依赖
cd air
make ci
# 4. 这样就可以快乐地探索和玩耍啦!
make install顺便说一句:欢迎 PR~
发布新版本
# 1. checkout 到 master 分支
git checkout master
# 2. 添加需要发布的版本号
git tag v1.xx.x
# 3. 推送到远程
git push origin v1.xx.x
# CI 将处理并发布新版本。等待大约 5 分钟,你就可以获取最新版本了开发动机
当我用 Go 和 gin 框架开发网站时,gin 缺乏实时重载的功能是令人遗憾的。我曾经尝试过 fresh,但是它用起来不太灵活,所以我试着用更好的方式来重写它。Air 就这样诞生了。
此外,非常感谢 pilu。没有 fresh 就不会有 air :)
Star 历史
赞助
非常感谢众多支持者。我一直铭记你们的善意。
许可证
GNU General Public License v3.0
File: README-zh_tw.md
:cloud: Air - Go 應用的即時重新載入工具
Air 是一個用於開發 Go 應用的自動重新編譯執行命令列工具。在你的專案根目錄下運行 air,將它執行於背景中,並專注於你的程式碼。注意:此工具與生產環境的熱部署無關。
目錄
安裝
使用 `go install`(推薦)
需要使用 go 1.25 或更高版本:
go install github.com/air-verse/air@latest請確認你的 Go bin 目錄已加入 PATH:
export PATH="$PATH:$(go env GOPATH)/bin"使用 `go get -tool`(安裝到專案中)
需要使用 go 1.25 或更高版本:
go get -tool github.com/air-verse/air@latest
# 然後這樣使用:
go tool air -v透過 install.sh
# 執行檔會安裝到 $(go env GOPATH)/bin/air
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# 或者把它安裝到 ./bin/ 路徑下
curl -sSfL https://raw.githubusercontent.com/air-verse/air/master/install.sh | sh -s
air -v透過 goblin.run
請參考 goblin.run。
# 執行檔會安裝到 /usr/local/bin/air
curl -sSfL https://goblin.run/github.com/air-verse/air | sh
# 安裝到自訂路徑
curl -sSfL https://goblin.run/github.com/air-verse/air | PREFIX=/tmp sh透過 Homebrew
brew install go-air透過 Scoop
scoop install air使用 mise
mise use -g air透過 Docker/Podman
請讀取 cosmtrek/air 映像檔,用法請見 Docker。
快速開始
# 進入你的專案目錄
cd /path/to/your_project
# 先嘗試讀取目前目錄中的 `.air.toml`;如果不存在,則使用預設配置
air如果想產生一份可以自行修改的配置檔,先執行一次 air init,之後直接執行 air 即可:
# 產生帶有預設配置的 .air.toml
air init
# 會自動讀取 .air.toml
air如果要明確指定配置檔,可以使用 -c:
air -c .air.toml全部可用的配置項目請參閱 air_example.toml 檔案。
功能列表
- 彩色的日誌輸出
- 自訂建置或任何命令
- 支援排除子目錄
- 允許在 Air 開始後監視新目錄
- 更佳的建置過程
- 可設定的
.env檔案載入
使用方式
運行時參數
你可以在 air 命令後添加參數,這些參數會傳遞給建構出來的執行檔。
# 會執行 ./tmp/main bench
air bench
# 會執行 ./tmp/main server --port 8080
air server --port 8080你可以使用 -- 參數來分隔傳遞給 air 命令和傳遞給執行檔的參數。
# 會執行 ./tmp/main -h
air -- -h
# 會以自訂配置執行 air,並把 -h 傳給建構出的執行檔
air -c .air.toml -- -h除錯
air -d 會印出所有日誌。
配置
用參數覆寫指定的配置
air 的配置欄位都支援以命令列參數的形式傳入。可以用下列命令查看全部可用參數:
air -h
# 或者
air --help如果你想設定建置命令和執行命令,可以在不需要配置檔案的情況下如下使用命令:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api"對於需要輸入列表的參數,可以使用逗號將項目分隔:
air --build.cmd "go build -o bin/api cmd/run.go" --build.entrypoint "./bin/api" --build.exclude_dir "templates,build"列表類參數也可以重複傳入,取值會依照出現順序依序附加。當命令列是由腳本或 Makefile 產生時,這種寫法很方便:
# 等同於 --env_files ".env,.env.local,.env.secret"
air --env_files ".env,.env.local" --env_files ".env.secret"啟動橫幅
使用 misc.startup_banner 控制 Air 啟動時印出的內容。
[misc]
# 不設定(預設):顯示內建的 ASCII 橫幅與版本號。
# 設為空字串:什麼都不印出。
startup_banner = ""
# 設為自訂文字:印出這段文字,取代內建橫幅。
# startup_banner = "API watcher"Entrypoint
使用 build.entrypoint 指定 build.cmd 建構出的執行檔,以及它的執行方式。這個值可以是字串(只指定執行檔),也可以是字串陣列。使用陣列時,第一個元素是執行檔(相對於 root 解析;若其中不含路徑分隔符號,則從 $PATH 中尋找),其餘元素都會被視為預設參數。build.args_bin 與命令列傳入的參數會附加在這些內聯參數之後。舊的 build.bin 欄位已被棄用,未來版本會移除,請優先使用 entrypoint 的寫法。
[build]
entrypoint = ["./tmp/main"]
args_bin = ["server", ":8080"]
# 也可以把預設參數直接內聯寫在執行檔後面。
entrypoint = ["./tmp/main", "server", ":8080"]
# 不帶路徑分隔符號時會從 PATH 中尋找,例如 dlv。
entrypoint = [
"dlv", "exec", "--accept-multiclient", "--log", "--headless", "--continue",
"--listen=:8999", "--api-version", "2", "./tmp/main",
]環境變數檔案
設定 env_files 之後,Air 會在建置與執行之前,自動從 .env 檔案載入環境變數。
# 依序載入 .env.development 與 .env。
# 越後面的檔案中的值會覆寫前面的值。
# 不會覆寫執行 air 之前就已存在的變數。
env_files = [".env.development", ".env"]依平台覆寫建置配置
你可以用 [build.windows]、[build.darwin] 和 [build.linux] 依作業系統覆寫建置配置。在對應平台上執行時,這些區塊會覆寫 [build] 中的值。平台區塊中只支援下列欄位:pre_cmd、cmd、post_cmd、bin、entrypoint、full_bin、args_bin。
[build]
cmd = "go build -o ./tmp/main ."
bin = "./tmp/main"
[build.windows]
cmd = "go build -o ./tmp/main.exe ."
bin = "tmp\\main.exe"
entrypoint = ["tmp\\main.exe"]當目前系統的預設配置與基礎配置不同時,air init 會自動為目前系統產生對應的平台區塊。
監視規則:執行命令而非重新建置
有時候檔案變更需要的是執行某個命令,而不是重新建置應用程式——例如直接從磁碟提供的前端資源,或是 templ/sqlc/go generate 這類流程。可以為它們各自宣告一個 [[build.rules]] 區塊:
[build]
cmd = "go build -o ./tmp/main ."
# 主要建置流程忽略前端目錄……
exclude_dir = ["web"]
# ……但這條規則會監視它,並在變更時重新建置前端資源
[[build.rules]]
name = "assets"
include_dir = ["web"]
include_ext = ["js", "ts", "css"]
cmd = "npm run build"
[[build.rules]]
name = "templ"
include_ext = ["templ"]
cmd = "templ generate"被規則比對到的檔案只會執行該規則的 cmd,絕不會觸發重新建置,即使它同時也符合主要建置的監視條件。規則涉及的目錄即使寫在 exclude_dir 裡也依然會被監視。如果規則的命令產生了主要建置正在監視的檔案(例如 templ generate 產生 .go 檔案),重新建置自然會隨之觸發。
每條規則支援 include_dir、include_ext、include_file、exclude_regex 以及 delay(防抖動時間,單位毫秒,預設 1000)。include_* 比對條件至少要填一項。規則會等待命令執行完畢;執行期間到達的變更會排入佇列,結束後再跑一次。
代理:自動重新載入瀏覽器
Air 可以在你的 Web 應用前面掛一個小型代理,每次建置成功後自動重新載入瀏覽器,這樣就不必再手動按重新整理了。
[proxy]
enabled = true
# 你在瀏覽器中開啟的連接埠
proxy_port = 8090
# 你的應用實際監聽的連接埠
app_port = 8080照常啟動 air,然後在瀏覽器中開啟 http://localhost:8090,而不是應用自己的連接埠。請求會被轉發到 app_port,同時 Air 會在每個 HTML 回應的 `` 標籤前注入一小段腳本;建置完成後,這段腳本就會重新載入頁面。
要讓它生效,有兩個前提:
- HTML 中必須有 `` 標籤——否則沒有地方可以注入腳本,頁面會原樣回傳;
- 你修改的檔案必須在監視範圍內,所以靜態資源需要被
include_dir、include_ext或include_file涵蓋。
如果你的應用啟動較慢(連接資料庫、載入配置等),並出現 "unable to reach app" 錯誤,可以把等待時間調長:
[proxy]
# 建置完成後重試連接應用的時間長度,單位毫秒(預設 5000)
app_start_timeout = 10000Docker
使用官方映像檔
請讀取 Docker 映像檔:cosmtrek/air。
docker/podman run -it --rm \
-w "" \
-e "air_wd=" \
-v $(pwd): \
-p :<APP SERVER PORT> \
cosmtrek/air \
-c <CONF>`` 是你的容器中的專案路徑,例如 /go/example。如果你想要進入容器,請加上 --entrypoint=bash。
我其中一個專案是在 Docker 中運行:
docker run -it --rm \
-w "/go/src/github.com/cosmtrek/hub" \
-v $(pwd):/go/src/github.com/cosmtrek/hub \
-p 9090:9090 \
cosmtrek/airShell 函數
如果你想像常規應用程式一樣持續使用 air,你可以在你的 ${SHELL}rc(Bash、Zsh 等)中建立一個函數:
air() {
podman/docker run -it --rm \
-w "$PWD" -v "$PWD":"$PWD" \
-p "$AIR_PORT":"$AIR_PORT" \
docker.io/cosmtrek/air "$@"
}其中 $PWD 會被替換為當前目錄,$AIR_PORT 是要發佈的連接埠,而 $@ 用來接受應用程式本身的參數,例如 -c:
cd /go/src/github.com/cosmtrek/hub
AIR_PORT=8080 air -c "config.toml"Docker Compose
services:
my-project-with-air:
image: cosmtrek/air
# working_dir 的值必須與掛載的 volume 相同
working_dir: /project-package
ports:
- <any>:<any>
environment:
- ENV_A=${ENV_A}
- ENV_B=${ENV_B}
- ENV_C=${ENV_C}
volumes:
- ./project-relative-path/:/project-package/不使用 air 映像檔
Dockerfile
# 選擇你想要的版本,>= 1.25
FROM golang:1.25-alpine
WORKDIR /app
RUN go install github.com/air-verse/air@latest
COPY go.mod go.sum ./
RUN go mod download
CMD ["air", "-c", ".air.toml"]docker-compose.yaml
version: "3.8"
services:
web:
build:
context: .
# 修改為你的 Dockerfile 路徑
dockerfile: Dockerfile
ports:
- 8080:3000
# 為了即時重新載入,將程式碼目錄掛載到 /app 目錄很重要
volumes:
- ./:/appQ&A
出現「找不到命令:air」或「找不到檔案或目錄」
請確認 Go bin 目錄已加入 PATH:
export GOPATH=$HOME/xxxxx
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:$(go env GOPATH)/bin <---- Confirm this line in you profile!!!當 bin 路徑中包含單引號時,在 WSL 下的錯誤
應該使用 \ 來跳脫 bin 中的 '。相關議題:#305
如何只進行熱編譯而不執行任何東西?
請參考 #365。
[build]
cmd = "/usr/bin/true"如何在靜態檔案變更時自動重新載入瀏覽器?
啟用代理即可,詳見代理:自動重新載入瀏覽器。請確認你的靜態檔案有被 include_dir、include_ext 或 include_file 涵蓋,否則修改它們不會觸發重新載入。更多細節請參考 #512。
開發
請注意:目前需要 Go 1.25+(請參考 go.mod)。
# Fork this project
# Clone it
mkdir -p $GOPATH/src/github.com/cosmtrek
cd $GOPATH/src/github.com/cosmtrek
git clone [email protected]:<YOUR USERNAME>/air.git
# Install dependencies
cd air
make ci
# Explore it and happy hacking!
make install歡迎提出 Pull Request
發佈版本
# Checkout to master
git checkout master
# Add the version that needs to be released
git tag v1.xx.x
# Push to remote
git push origin v1.xx.x
# The CI will process and release a new version. Wait about 5 min, and you can fetch the latest version開發動機
當我開始用 Go 開發網站並使用 gin 框架時,感到可惜的是 gin 缺乏自動重新編譯執行的方式。因此,我四處搜尋並嘗試使用 fresh,但它似乎不夠彈性,所以我打算重新寫得更好。最後,Air 就這麼誕生了。
另外,非常感謝 pilu,如果沒有 fresh,就不會有 air :)
星星歷史
贊助專案
非常感謝大量的支持者。我一直記得你們的善意。