GraalVMとは?JVMとの違いとNative Imageの作り方【2026年版】
GraalVMは「新しい仮想マシン」という説明で紹介されることが多いのですが、実体はNative Imageというコンパイラを同梱したJDKの配布物です。普通のJDKと同じようにjavacとjavaが入っていて、IDEのJDK設定にそのまま指定できます。違いが出るのは、実行を速くする仕組みの選択肢が増える点です。この記事では、通常のJDKとの違い、2025年に切り替わったバージョン体系、Oracle版とCommunity Editionで使える機能の差、そしてネイティブ実行ファイルを作る具体的な手順を、公式ドキュメントとリリースノートの記述に沿って整理します。
まとめ
GraalVMはOpenJDKをベースにしたJDK配布物で、Java用のJITコンパイラ「Graal」と、Javaコードを単体の実行ファイルへ事前コンパイルする「Native Image」を含みます。2026年8月5日時点の最新はGraalVM 25.2.4(2026年7月28日公開、OpenJDK 25.0.4+7ベース)です。バージョンの数え方は「GraalVM for JDK 24」までのJDK追従型から、GraalVM自身の番号を使う25.0(LTS)と25.1・25.2(Innovation)へ切り替わりました。
導入で迷いやすいのがエディションの差です。Oracle GraalVMはGFTCライセンスで本番利用まで無償、Community EditionはGPLv2+Classpath例外ですが、プロファイル誘導最適化(PGO)とNative ImageのG1 GCはCommunity Editionでは使えません。LTS系統の四半期セキュリティ更新もOracle GraalVMにしか供給されていません。起動速度が要件でないなら、Native Imageを使わずJDK 25のAOTキャッシュで済ませる判断も現実的です。
GraalVMの正体はNative Imageを内蔵したJDK配布物
GraalVMはOracleが配布しているJDKディストリビューションです。Amazon CorrettoやEclipse Temurinと同じ位置づけで、OpenJDKのソースをベースにビルドされています。そのためjava -versionもクラスパスの扱いも既存のJDKと変わりません。名称に「VM」が付くため独自の仮想マシンだと誤解されがちですが、HotSpot VMをまるごと置き換えるものではありません。
Graal JITコンパイラとNative Imageという2本の柱
GraalVMが標準のJDKに追加している中身は、大きく2つです。ひとつはJavaで書かれたJITコンパイラ「Graal」で、実行中のプロファイルをもとにバイトコードを機械語へ変換します。もうひとつがNative Imageで、こちらは実行前にアプリケーション全体を静的解析し、到達可能なクラス・メソッド・リソースだけを含んだ単体バイナリを生成します。
公式リファレンスはNative Imageの利点として、JVMが必要とするリソースの一部で動くこと、ミリ秒単位で起動すること、ウォームアップなしで最初からピーク性能を出せること、軽量なコンテナイメージに詰められること、攻撃対象領域が小さくなることを挙げています。JITとAOTの原理的な違いについてはJITコンパイラとは?仕組み・種類とAOT・インタプリタの違いをわかりやすく解説で整理しています。
TruffleとPolyglot APIが別配布へ移った経緯
かつてのGraalVMは、JavaScript・Python・Ruby・Rなどのランタイムを同梱した「多言語プラットフォーム」として紹介されていました。この構成は現在のGraalVMには当てはまりません。GraalVM Community 25.2.4のGitHubリリースページは、PythonやJavaScript/Node.jsといった追加の言語ランタイムをそれぞれ関連リポジトリのスタンドアロン配布として提供すると明記しており、実際に配布アセットはJDK本体のtarballとzipだけです。
つまり多言語実行は、GraalVMを入れれば自動的に使える機能ではなく、Maven依存やスタンドアロン配布を明示的に追加して初めて有効になります。この仕組みと、言語を自作する際に使うTruffleフレームワークの解説はTruffleとは?GraalVMで自作言語を実装する仕組みとPolyglot APIが担当です。本記事はJDK配布物としてのGraalVMに絞ります。
通常のJDK(HotSpot)との違いと使い分けの判断軸
「GraalVMと普通のJVMは何が違うのか」は検索でも頻出しますが、違いは実行エンジンの選択肢にあります。仮想マシンそのものの役割についてはJava仮想マシン(JVM)とは何かをわかりやすく解説が前提知識になります。
OpenJDKからGraal JITが外れJVMCIだけが残った経緯
Graalコンパイラは、かつてOpenJDKにも実験的機能として同梱されていました。JDK 9でjaotcによるAOTコンパイルが(JEP 295)、JDK 10でGraalの実験的JITが(JEP 317)入っています。しかしJEP 410により、JDK 17でjdk.aotモジュールとGraal JITはOpenJDKから削除されました。JEPの記述によれば、導入以降ほとんど使われず保守コストが見合わなかったことが理由で、JDK 16のOracleビルドでは既に外されていたが誰からも苦情が出なかったとされています。
ただし同じJEPは、外部でビルドしたコンパイラをJITとして使えるようにJVMCI(Java-Level JVM Compiler Interface)は実験的機能として残すと述べています。GraalVMのGraal JITは、このJVMCIを介して差し込まれる外部コンパイラです。標準のOpenJDKを入れてもGraal JITは付いてこない、という結論はここから来ています。
起動速度とピーク性能が入れ替わるトレードオフ
Native Imageの実行ファイルはHotSpot VMではなく、GraalVMが提供するランタイムの上で動きます。JITコンパイラは動かないため、実行時プロファイルにもとづく最適化は行われません。公式のPGOドキュメントはこの点を率直に説明していて、AOTコンパイラは基本的にコードの静的な姿しか見えず、if文の各分岐が等しく起こりうるものとして扱われるため、ヒューリスティクスを別にすればJITと同等品質の機械語を出すのは難しいと書かれています。
判断軸はここで割り切れます。プロセスが短命で起動時間が支配的なCLIツール、サーバーレス関数、頻繁にスケールアウトするコンテナならNative Imageが効きます。長時間稼働するシステム側の判断基準は後段の「Native Imageを避けるべき条件」にまとめました。
25.0 LTSと25.2 Innovationに分かれたバージョン体系と入手経路
2023年から2025年前半までのGraalVMは「GraalVM for JDK 21」「GraalVM for JDK 24」のようにJDKのフィーチャーリリースへ追従した名前を使っていました。この命名はJDK 24で終わっています。
「GraalVM for JDK 24」から「GraalVM 25」への命名変更
公式リリースカレンダーは、2025年9月より前は「GraalVM for JDK 21」のような表記だったが、以降は「GraalVM 25」という簡潔な形式に変わったと説明しています。現在のダウンロードページが提示する選択肢も、25.2(Innovation)、25.0(LTS)、JDK 21(LTS)、JDK 17(LTS)の4系統です。GraalVM 25.2.4のリリースノートは、これをOpenJDK 25.0.4+7ベースのinnovation releaseと説明しています。GraalVM Community EditionのGitHub Releasesでも、2026年1月20日のjdk-25.0.2を最後にタグがgraal-25.1.3(2026年6月30日)、graal-25.2.4(2026年7月28日)へ移り、配布ファイル名もgraalvm-community-jdk-25i2-25.0.4_linux-x64_bin.tar.gzのように「25i2」というInnovation番号を含む形式になっています。
| 系統 | 位置づけ | ベースJDK | Oracle GraalVMの最新 | Community Editionの最新 |
|---|---|---|---|---|
| GraalVM 25.2 | Innovation | JDK 25.0.4+7 | 25.2.4(2026-07-28) | 25.2.4(2026-07-28) |
| GraalVM 25.1 | Innovation | JDK 25.0.3 | 25.1.3(2026-06-30) | 25.1.3(2026-06-30) |
| GraalVM 25.0 | LTS | JDK 25.0.x | 25.0.4(2026-07-21) | 25.0.2(2026-01-20) |
| GraalVM for JDK 21 | LTS | JDK 21 | 21.0.12(2026-07-21) | 21.0.2(2024-01-16) |
| GraalVM for JDK 17 | LTS | JDK 17 | 17.0.20(2026-07-21) | 17.0.9(2023-10-24) |
ベースJDKは同じ版番号でも、Community EditionはOpenJDK、Oracle GraalVMはOracle JDKが土台です(リリースノートも25.2.4をそれぞれ「OpenJDK 25.0.4+7ベース」「Oracle JDK 25.0.4+7ベース」と書き分けています)。表の25.1はダウンロードページの現行選択肢には残っておらず、次のフィーチャーリリースに置き換えられた旧Innovationです。
右2列の差が実務上の落とし穴です。公式リリースカレンダーは、四半期ごとのCPU(Critical Patch Update)を「Oracle GraalVM向けに1月・4月・7月・10月の第3火曜に公開する」と定義しています。実際、種別がCPU単独の回は2026年4月21日以降すべてOracle GraalVM列にしか版番号が入らず、Community Edition列は空欄で、2026年10月20日と2027年1月19日の予定も同じ形です。CEでLTSに固定すると、25.0系は2026年1月20日の25.0.2、JDK 21系は2024年1月16日の21.0.2で更新が止まります。
ただしCEが放置されているわけではなく、更新はInnovation系統の月次フィーチャーリリースで届きます。2026年7月28日の25.2.4は種別が「Feature + CPU」で、CE列にも25.2.4が入っています。次の25.3.4は2026年8月25日予定で、以降もほぼ毎月続きます。同カレンダーは25.1以降、両エディションが月次でフィーチャーリリースを出し、利用可能な四半期CPUをそこへ取り込むと説明しています。LTSに固定して四半期のセキュリティ更新を受けたいならOracle GraalVM、無償のCEで運用するならInnovation系統を月次で追う、という二択になります。ただし「最新のフィーチャーリリースが過去のフィーチャーリリースをすべて置き換える」方式なので、Innovation系統のある版を長期固定する用途には向きません。
SDKMAN!・コンテナ・GitHub Actionsでの導入コマンド
導入経路は公式ダウンロードページに5種類が並んでいます。スクリプトから固定バージョンを取る場合はアーカイブURLが確実です。
# スクリプト向けURL(最新をたどる場合)
wget https://gds.oracle.com/download/graal/25i2/latest/graalvm-jdk-25i2-25_linux-x64_bin.tar.gz
# バージョンを固定する場合はarchiveを使う
curl https://gds.oracle.com/download/graal/25i2/archive/graalvm-jdk-25i2-25.0.4_linux-x64_bin.tar.gz
# コンテナ(Native Imageあり/なしで別イメージ)
docker pull container-registry.oracle.com/graalvm/native-image:25.2
docker pull container-registry.oracle.com/graalvm/jdk:25.2
# Community Editionは配布元が別(GitHub Container Registry)
docker pull ghcr.io/graalvm/jdk-community:25i2-25.0.4
URLの末尾に.sha256を付けるとチェックサムが取得できます。ここで気をつけたいのが配布元です。gds.oracle.comのアーカイブとcontainer-registry.oracle.comのイメージはどちらもOracle GraalVMで、CEを使うなら明示的に切り替える必要があります。CIで使うGitHub Actionも同様で、distributionの既定値はgraalvm=Oracle GraalVMです。
- uses: graalvm/setup-graalvm@v1
with:
version: '25.2'
distribution: 'graalvm' # Oracle GraalVM(GFTC)
# distribution: 'graalvm-community' # Community Edition(GPLv2+Classpath例外)
github-token: ${{ secrets.GITHUB_TOKEN }}
ローカル開発でJDKを切り替えているならJVM開発者がSDKMAN!を導入すべき理由とバージョン管理の課題解消の手順が使えます。ただし公式ダウンロードページのSDKMAN!欄は、2026年8月5日時点でsdk install java 25.2.4-graalに「coming soon」と注記されています。リリース直後の版がSDKMAN!に即日並ぶとは限らないため、最新版を急いで試すときは配布アーカイブを直接取得する方が確実です。
Oracle GraalVMとCommunity Editionで使える機能とライセンスの差
GraalVMには配布が2系統あり、どちらもNative Imageを使えますが、最適化機能に差があります。ここを見落とすと「ドキュメントどおりのオプションが通らない」という事故になります。
| 項目 | Oracle GraalVM | Community Edition |
|---|---|---|
| ライセンス | GFTC | GPLv2+Classpath例外 |
| 商用・本番利用 | 無償で可 | 無償で可 |
| 有償での再配布 | 不可 | GPLv2の条件下で可 |
| Native Image | 可 | 可 |
| PGO | 可 | 不可 |
| G1 GC(Native Image) | Linux AMD64/AArch64のみ | 不可 |
| Native Imageの既定GC | Serial GC | Serial GC |
| 最適化レベル -O3 | PGOビルドで自動適用 | -O2と同一 |
| LTS系統の四半期CPU | 提供あり | 提供なし |
| 不具合報告窓口 | My Oracle Support | GitHub Issues |
PGO・G1 GC・最適化レベルに現れる機能差
公式のメモリ管理ドキュメントは、Native ImageのGCについてSerial GCが既定であり、--gc=G1で有効化するG1 GCは現時点でLinux AMD64およびAArch64でのみ利用可能、かつCommunity Editionでは使えないと明記しています。極端に短命なプロセス向けの--gc=epsilon(回収を一切行わないGC)も選べます。最適化レベルも同様で、公式の最適化ドキュメントは既定の-O2に対し、Oracle GraalVMがPGOビルドで自動的に使う-O3について「CEでは-O3と-O2は同一」と明記しています。CEでビルドオプションだけ強めても、Oracle GraalVMと同じ結果にはなりません。JVM側のGC選定と混同しやすいので、Javaのガベージコレクション(GC)とは|仕組み・種類・チューニングの基礎で扱うHotSpotのGCとは別系統だと押さえておいてください。
GFTCとGPLv2の違いとJDK 17系のOTN切り替え
Oracle GraalVMのGFTCは商用・本番利用を許可し、有償でない限り再配布も認めています。jlinkやNative Imageが生成したランタイムイメージの利用も対象です。ひとつ注意が必要なのはJDK 17系で、GraalVM for JDK 17.0.13以降のCPU(Critical Patch Update)リリースはGraalVM OTNライセンスへ変更されました。JDK 21と25.0・25.2はGFTCのまま据え置かれています。Oracle JDKとOpenJDKのライセンス関係はOpenJDKは商用利用できる?無料の範囲とOracle JDKとの違い・ライセンス・サポート期限【2026年最新】と併せて確認すると全体像がつかめます。
Native Imageでネイティブ実行ファイルを作る手順
native-imageツールはGraalVMインストール先のbinディレクトリに同梱されており、追加インストールは不要です。ただし生成の最終段でシステムのリンカを使うため、ローカルのCツールチェーンが要ります。
# Ubuntu
sudo apt-get install build-essential zlib1g-dev
# Oracle Linux
sudo yum install gcc glibc-devel zlib-devel
# macOS
xcode-select --install
# Windows(MSVC 14.x以降が必要)
winget install --id Microsoft.VisualStudio.2022.BuildTools --source winget
native-imageコマンド単体とMavenプラグインの実行手順
最小構成なら、コンパイルしたクラスをそのまま渡すだけです。
javac HelloWorld.java
native-image HelloWorld
./helloworld
公式ドキュメントがこのHelloWorldの実測例として掲げるのがElapsed Time: 0.00 s Max RSS: 7620 KBという値です。常駐メモリは約7.6MB、起動時間は計測の分解能を下回っています。JARやモジュールを対象にする場合はnative-image [options] -jar jarfile [imagename]の形式を使います。
実プロジェクトではビルドツールのプラグイン経由が現実的です。Mavenではorg.graalvm.buildtools:native-maven-pluginをnativeプロファイルに置き、compile-no-forkゴールをpackageフェーズへ紐づけます。
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>1.1.7</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
mvn -Pnative package # ネイティブ実行ファイルを生成
mvn -Pnative test # ネイティブ実行ファイルとしてテストを実行
./target/(実行ファイル名) # 既定の名前はartifactId由来
Gradleならorg.graalvm.buildtools.nativeプラグインを適用し./gradlew nativeCompileを実行すると、app/build/native/nativeCompile/配下に実行ファイルが出ます(Gradleのマルチプロジェクト構成の場合。単一プロジェクトならbuild/native/nativeCompile/)。native-build-toolsは更新が速く、1.1.7はMaven Centralに2026年7月30日、GitHub Releasesには2026年8月4日に公開されています。1〜2週間おきに版が出るため個別に追いかける意味は薄く、バージョンをプロパティに外出しして、GraalVM本体の月次リリースのタイミングでまとめて上げる運用が無難です。Spring Bootで使う場合は、フレームワーク側のサポート版と噛み合っている必要があるため、Spring Bootバージョン一覧とサポート期限【2026年7月】最新4.1と3.5 EOL後の選び方のサポート表と突き合わせてください。
リフレクションを通すreachability metadataの用意
Native Imageのビルドが通っても実行時にClassNotFoundExceptionが出る、という詰まり方が典型です。原因は静的解析の限界にあります。公式ドキュメントが説明するとおり、リフレクション、JNI、FFM API、動的プロキシ、クラスパス上のリソースなどは実行時のデータに依存するため、到達可能かどうかをビルド時に判定しきれません。そこでreachability metadataという形で明示的に教える必要があります。
メタデータの提供手段は4通りあり、実務ではMETA-INF/native-image/(groupId)/(artifactId)/配下にreachability-metadata.jsonを置く方法か、-H:Preserve=フラグでクラスパスやパッケージ単位に保持する方法を使います。手書きは現実的でないため、通常のJVM上でアプリケーションを動かして自動収集するTracing Agentを使います。
# 通常のJVM実行に追従してJSONを書き出す
$JAVA_HOME/bin/java -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ \
-jar app.jar
# 別の実行パスを試して既存の設定へマージする
$JAVA_HOME/bin/java -agentlib:native-image-agent=config-merge-dir=/path/to/config-dir/ \
-jar app.jar
ドキュメントは-agentlibを-jarやクラス名、アプリケーション引数より前に置くよう明記しています。ここを間違えるとエージェントが読み込まれず、空の設定が出力されます。またエージェントは実行した経路しか記録しないため、分岐の異なるシナリオを複数回流してマージするのが前提です。
登録漏れを早期に検出したい場合は、ビルド時に--exact-reachability-metadataを渡すと厳格モードになります。まず現状把握だけしたいときは、実行時に-XX:MissingRegistrationReportingMode=Warnを付けると、登録漏れの箇所が警告として一覧できます。
Native Image 25.2で変わった既定値と削除されたオプション
25.2のリリースノートには、既存のビルドスクリプトに影響する変更が並んでいます。とくに次の4点は、25.0以前から上げるときに確認が要ります。
- 圧縮32ビットオブジェクト参照が既定で有効になりました。メモリ使用量と性能が改善する一方でヒープが32GBに制限されるため、それを超えるヒープが必要なら
-H:-UseCompressedReferencesで無効化します。ヒープを大きく取る前提のバッチをNative Image化している場合、ここに先に当たります。 - 常にisolatesを使う仕様になりました。
-H:+SpawnIsolatesは互換のため残っていますが、-H:-SpawnIsolatesはビルド時エラーになります。 - 非推奨だった
-H:OutlineWriteBarriersが削除され、-H:WriteBarrierOutlining=に置き換わりました。 - Vector API対応は
jdk.incubator.vectorがブートモジュール層にあれば既定で有効です。外すには-H:-VectorAPISupportを渡します。
いずれも既定値の変更なので、オプションを何も指定していないビルドほど挙動が変わります。
Native Imageを避けるべき条件とJDK 25のAOTキャッシュという代替
ここは断言します。起動時間が事業要件になっていないなら、Native Imageを導入すべきではありません。得られるものに対して払うコストが大きすぎるからです。
避けた方がよい条件は具体的に挙げられます。第一に、リフレクションやバイトコード生成を多用するライブラリ(古いORM、DIコンテナ、一部のシリアライザ)を抱えている場合です。reachability metadataの収集と維持がそのまま恒常的な運用コストになります。第二に、長時間稼働するプロセスで単位時間あたりの処理量が指標になっている場合です。PGOを使わないAOTコードはJITが暖まった後のコードに劣るため、前掲のとおりPGOが使えるOracle GraalVMへ寄せる判断が別途必要になります。第三に、ビルド時間とビルドマシンのメモリです。Native Imageのビルドは全体の静的解析を伴うため、通常のmvn packageとは比べものになりません。
そのうえで、起動を速くする選択肢はNative Imageだけではなくなりました。Project LeydenのJEP 483がJDK 24でAOTキャッシュを導入し、JDK 25ではJEP 514がコマンドを簡素化、JEP 515がメソッドの実行プロファイルを事前に持ち込めるようにしています。JDK 24ではトレーニング実行とキャッシュ生成でjavaを2回起動する必要がありましたが、JDK 25では1回で済みます。
# JDK 25:トレーニング実行とキャッシュ生成を1コマンドで
java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App
# 本番実行はキャッシュを指定するだけ
java -XX:AOTCache=app.aot -cp app.jar com.example.App
この方式はHotSpot VM上で動くため、JITもリフレクションもこれまでどおり機能します。クラスの探索・ロード・リンクを省ける分だけ起動が速くなる、という限定的な効果ですが、アプリケーションのコードにもライブラリ構成にも手を入れずに済むのが決定的な違いです。JEP 514はクラウドの小さいインスタンスで学習し大きいインスタンスでキャッシュを作るといった使い分けのために、従来の2段階ワークフローも残しています。キャッシュ生成側にだけオプションを渡したい場合はJDK_AOT_VM_OPTIONS環境変数が使えます。順序としては、まずAOTキャッシュを試し、それでも起動時間の要件を満たせない場合に限ってNative Imageへ進むのが、投じる労力に見合った進め方です。
よくある質問
GraalVMの読み方は?
公式に定められた日本語の読みはありません。Oracleの日本語ドキュメントでも表記は英字の「GraalVM」のままで、カタカナ表記は使われていません(リフレクションとNative Imageを扱う日本語の解説ページを調べても、カタカナ表記は一度も現れません)。会話では「グラールVM」と読まれることが多いものの、ドキュメント参照や検索の互換性を考えると、文章中は英字表記で統一しておくのが確実です。
GraalVMは無料で商用利用できますか?
できます。Oracle GraalVMはGFTCのもとで商用・本番利用が無償で、クリックスルーの同意手続きもありません。判断に迷いやすいSaaS提供についても、公式FAQはプログラム自体のコピーを受け取らない第三者に使わせるホスティング利用を「自社の内部業務のための利用」とみなし、そのサービスに料金を課してよいと明記しています。GFTCが禁じているのはプログラムそのものを有償で再配布することです。Community EditionはGPLv2+Classpath例外なので、こちらは有償配布も同ライセンスの条件下で可能です。
GraalVMとOpenJDKはどちらを使うべきですか?
Native ImageもGraal JITも使う予定がないなら、通常のOpenJDKで十分です。JEP 410によりJDK 17からOpenJDKにはGraal JITが含まれておらず、GraalVMを入れる理由はこの2つに絞られます。なお、Graal JITだけを使いたい場合もGraalVMの配布物を用意するのが現実的です。JEP 410が残したJVMCIはあくまで外部コンパイラを差し込むための口であり、差し込む側のGraalコンパイラはOpenJDKに同梱されていないためです。
GraalVMでPythonやJavaScriptを動かせますか?
動かせますが、GraalVMを入れただけでは使えません。GraalPyやGraalJSはGraalVM本体とは別リポジトリ(github.com/oracle/graalpython、github.com/oracle/graaljs)でスタンドアロン配布として公開されており、JDKのtarballには含まれていません。バージョンは本体と揃える必要があり、GraalVM 25.2.4に対応するタグは同じgraal-25.2.4です。GraalJS側は25.2.4でNode.jsを24.17.0へ更新しています。利用するにはMaven依存を追加するか、スタンドアロン配布を個別に導入し、Polyglot API経由で呼び出します。
Native Imageのビルドが遅いときの対処法は?
開発中のビルドには-Ob(quick build mode)を使います。公式の最適化ドキュメントは、時間のかかる最適化を省いてビルドを高速化するモードと説明しており、生成物のサイズが小さくなる場合もあるとしています。既定は-O2で、こちらは性能とファイルサイズのバランスを取る設定です。そもそもビルドが重いのは、アプリケーション全体の静的解析を経て機械語まで落とすためで、公式はこの工程をJavaソースのコンパイルと区別して「build time」と呼んでいます。CIでは通常ビルドとネイティブビルドを分離し、後者はリリース時のみ走らせる構成にすると開発サイクルへの影響を抑えられます。