Gleam(グリーム)は、Erlang仮想マシン(BEAM)とJavaScriptランタイムの両方で動く、静的型付けの関数型プログラミング言語です。2024年3月4日にv1.0.0が出て、2026年9月27日時点の安定版はv1.18.1(2026年8月1日)です。名前はErlang VMの「BEAM」と韻を踏み、意味も近い英単語のgleam(かすかな光)から取られています。懸賞キャンペーンサービスのgleam.ioとは別のものです。この記事では、Gleam 1.18.1で実際に動かしたコードと出力を示しながら、インストール、構文、OTPによる並行処理、JavaScriptターゲットの制約、Elixirとの違いまでを整理します。
まとめ
- 正体:BEAMとJavaScript(ECMAScript 2022以上)にコンパイルされる型安全な関数型言語。型が合わないコードはビルドが通らない。
- 最新版:安定版はv1.18.1(2026年8月1日)。v1.19.0は2026年9月26日にrc2が出た段階。
- 導入:macOSは
brew install gleamでErlangとrebar3も入る。WindowsはwingetかScoop。v1.18はErlang/OTP 29と28に対応。 - 並行処理:
gleam_otpのactorで、メッセージの型までコンパイル時に検査される。ただしErlangターゲット専用。 - JavaScript:TypeScript定義は
typescript_declarations = trueを設定したときだけ出る。整数の安全な範囲は−(2^53−1)〜2^53−1で、範囲外では丸めが起こり得る。 - 向き不向き:型クラス・マクロ・例外・可変状態を持たない小さな言語。Elixirのマクロ前提のライブラリやホットコードアップグレードを多用する現場には合わない。
Gleamの特徴と設計方針
静的型と型推論によるコンパイル時の検査
Gleamは変数や関数の型を推論し、型が合わなければコンパイルエラーにします。型注釈は省略できます。Erlang VM上の言語でありながら、実行前に型の不整合をコンパイルエラーとして検出できる点が特徴です。後述のactorに整数を渡すべき場所へ文字列 "4" を渡すと、v1.18.1は次のエラーを出してビルドを止めます。
24 │ process.send(counter, Add("4"))
│ ^^^
Expected type:
Int
Found type:
String
もう一つの特徴は、null や例外を言語に持たないことです。値が無い可能性は Option、失敗する可能性は Result 型で表し、case 式ですべての分岐を書かないとコンパイラが警告ではなくエラーを出します(網羅性検査)。
Gleamで追加予定のない言語機能
Gleam公式FAQは「Gleamは常に小さくまとまった言語であり続ける」とし、今後も追加しない機能を列挙しています。主なものは次のとおりです。
- 例外によるエラー処理、関数・演算子のオーバーロード、省略可能な引数
- Lisp風のマクロ、型クラスやトレイト、オブジェクト指向
- ミュータブルな変数(データ構造はすべてイミュータブル)
v1.0の告知では、この小ささを「午後のうちに学べる(learn in an afternoon)」と表現しています。Haskellの型クラスやRustのトレイトのような抽象化を期待すると物足りなく感じます。その代わり、誰が書いても似た形のコードになり、読み手の負担が小さくなります。
ErlangとJavaScriptの2つのコンパイルターゲット
同じGleamのコードを、Erlangの .beam バイトコードにも、JavaScriptのESモジュール(.mjs)にもコンパイルできます。ターゲットはプロジェクト作成時の --template(erlang か javascript、既定は erlang)か、実行時の --target で選びます。Erlangターゲットでは既存のErlang・Elixirのライブラリを使え、JavaScriptターゲットの出力はNode.js・Deno・Bunやブラウザで動きます。作者はLouis Pilfoldで、最初の公開版v0.1は2019年4月に出ました。コンパイラ自体はRustで書かれており、試作段階のErlang版から「静的型が無くてリファクタリングが遅く誤りやすかった」ためにRustへ書き直されたと公式FAQが説明しています。
インストールと最初のプロジェクト
OS別のインストールコマンド
公式のインストール手順(gleam.run/install)が案内する主なコマンドは次の表のとおりです。Erlangターゲットで実行するにはErlang/OTPが必要です。rebar3は、Erlangで書かれた依存パッケージをコンパイルするときに使われます。HomebrewのGleamパッケージはErlangとrebar3を依存として一緒に入れるので、macOSならコマンド1つで揃います。
| 環境 | Gleam | Erlang |
|---|---|---|
| macOS(Homebrew) | brew install gleam | 依存として同時に導入 |
| Windows(winget) | winget install –id Gleam.Gleam | winget install –id Erlang.ErlangOTP |
| Windows(Scoop) | scoop install main/gleam | scoop install main/erlang |
| Arch Linux | sudo pacman -S gleam erlang rebar3 | 同じコマンドで導入 |
| Alpine Linux | sudo apk add gleam erlang rebar3 | 同じコマンドで導入 |
パッケージマネージャーを使わない場合は、GitHubのリリースページからビルド済みバイナリを取得できます。公式に継続テストされているのはLinux・macOS・Windowsのx86_64とaarch64です。
対応するErlang/OTPのバージョン
GleamのErlangターゲットは、各リリース時点で最新2つのErlang/OTPメジャーバージョンを対象にしています。古いOTPを使い続けている環境では、Gleamを上げる前に確認が必要です。
| Gleam | 対応するErlang/OTP |
|---|---|
| v1.18以降 | OTP 29・28 |
| v1.11〜v1.17 | OTP 28・27 |
| v1.2〜v1.10 | OTP 27・26 |
| v1.0〜v1.1 | OTP 26・25 |
gleam new からgleam run までの流れ
インストール後は gleam --version で版を確認し、gleam new でプロジェクトを作ります。生成されるのは gleam.toml、src/<名前>.gleam、test/<名前>_test.gleam で、依存には gleam_stdlib、テスト用に gleeunit が入ります。
$ gleam --version
gleam 1.18.1
$ gleam new my_app
$ cd my_app
$ gleam run
Hello from my_app!
$ gleam run --target javascript # 同じコードをNode.jsで実行
日常的に使うサブコマンドは次のとおりです。パッケージはErlang・Elixirと共通のレジストリHexから取得します。
| コマンド | 用途 |
|---|---|
| gleam add <pkg> | Hexから依存を追加 |
| gleam run / gleam run -m <module> | 実行(モジュール指定可) |
| gleam build / gleam check | ビルド/型検査のみ |
| gleam test | テスト実行 |
| gleam format | 公式フォーマッタ |
| gleam shell | Gleamのコードを読み込んだErlang REPL |
| gleam export escript | 単一ファイルの実行物を生成(v1.17〜) |
エディタとLanguage Server
Language Serverはコンパイラに組み込まれており、gleam lsp で起動します。公式手順はVS Code・Neovim・Helix・Zed・Sublime Text・Emacs・Vimの設定を案内しており、Helixは追加設定なしで動きます。v1.18ではレコードのフィールドについても定義へのジャンプ・参照検索・リネームが使えるようになりました。
Gleamの基本構文と実行結果
カスタム型、case 式、Result、パイプ演算子 |>、use 式をまとめて使う例です。Gleam 1.18.1・gleam_stdlib 1.0.5で、ErlangとJavaScriptの両ターゲットで同じ結果になることを確認しました。
import gleam/int
import gleam/io
import gleam/list
import gleam/result
pub type Shape {
Circle(radius: Float)
Rect(width: Float, height: Float)
}
pub fn area(shape: Shape) -> Float {
case shape {
Circle(r) -> 3.14159 *. r *. r
Rect(w, h) -> w *. h
}
}
pub fn parse_age(input: String) -> Result(Int, String) {
use n <- result.try(int.parse(input) |> result.replace_error("数値ではありません"))
case n {
n if n < 0 -> Error("負の値です")
n -> Ok(n)
}
}
pub fn main() -> Nil {
let total =
[Circle(1.0), Rect(2.0, 3.0)]
|> list.map(area)
|> list.fold(0.0, fn(acc, a) { acc +. a })
echo total
let _ = echo parse_age("42")
let _ = echo parse_age("-1")
let _ = echo parse_age("abc")
io.println("done")
}
出力は 9.14159、Ok(42)、Error("負の値です")、Error("数値ではありません")、done です(echo は値の前にファイル名と行番号を標準エラーへ出します)。読むときの要点は3つあります。
- 浮動小数点の演算子は
*.や+.で、整数の*+と区別される。IntとFloatは暗黙に変換されない。 use n <- result.try(...)は、失敗ならErrorをそのまま返し、成功なら中身をnに束縛して続きを実行する。ネストしたcaseを平らにする構文。caseのifはガード。Shapeに新しいバリアントを足すと、areaの網羅漏れがコンパイルエラーになる。
古い記事でよく見る io.debug は、標準ライブラリ0.59.0(2025年4月)で非推奨になり、0.61.0(2025年6月)で削除されました。gleam_stdlib 0.61.0以降で使うと「gleam/io に debug が無い」というコンパイルエラーになります。デバッグ出力には、v1.9で入った echo キーワードを使います。
BEAM上の並行処理とOTP
型付きactorの書き方
Erlangの強みである軽量プロセスと監視ツリー(OTP)は、パッケージ gleam_otp(v1.3.0)と gleam_erlang から使います。gleam_otp のドキュメントは、actorをErlangの gen_server やElixirの GenServer に近いものとしつつ「完全に型付けされたインターフェース」を持つ点が違うと説明しています。次はカウンターのactorです。プロジェクト内で gleam add gleam_otp gleam_erlang を実行し、次のコードを src/counter.gleam に保存してください。この例はErlang専用なので、JavaScript用の例とは別のプロジェクトで試します。
import gleam/erlang/process.{type Subject}
import gleam/otp/actor
pub type Message {
Add(Int)
Get(reply_to: Subject(Int))
}
fn handle(count: Int, msg: Message) -> actor.Next(Int, Message) {
case msg {
Add(n) -> actor.continue(count + n)
Get(reply_to) -> {
process.send(reply_to, count)
actor.continue(count)
}
}
}
pub fn main() -> Nil {
let assert Ok(started) =
actor.new(0) |> actor.on_message(handle) |> actor.start
let counter = started.data
process.send(counter, Add(3))
process.send(counter, Add(4))
echo process.call(counter, waiting: 100, sending: Get)
Nil
}
gleam run -m counter の出力は 7 です。宛先の Subject(Message) が受け取れるメッセージの型を持っているため、Add("4") のような誤送信は、前章で示したとおりコンパイル時に止まります。Erlang・Elixirでは実行時にしか分からない種類の誤りです。
ホットコードアップグレードの扱い
Erlangのコード差し替え機能自体はGleamでも動きます。ただし公式FAQによれば、稼働中のコードの型を知る手段が無いため、差し替えそのものは型検査されません。Gleam向けのOTPライブラリはアップグレードのしやすさより型安全を優先して設計されている、とFAQは明記しています。無停止のホットアップグレードを運用の柱にしているシステムでは、この点が採用判断の分かれ目になります。
JavaScriptターゲットの使い方と制約
ビルドとTypeScript型定義
gleam build --target javascript の出力は build/dev/javascript/<パッケージ名>/ に .mjs として並びます。gleam run と gleam test が直接扱えるランタイムはNode.js・Deno・Bunで、既定はNode.jsです。TypeScriptの型定義(.d.mts)は既定では生成されず、gleam.toml に次の設定を書いたときだけ出力されます。
[javascript]
typescript_declarations = true
v1.18.1で生成された定義を見ると、カスタム型のJavaScriptクラスのコンストラクタには @deprecated が付き、代わりに Shape$Circle(radius)(生成)、Shape$isCircle(value)(判定)、Shape$Circle$radius(value)(フィールド取得)という関数が出力されます。これはv1.13で導入された「Gleamのデータを外部から扱うための公式API」で、JavaScript側からGleamの値を作る・調べるときはこちらを使います。v1.16からは javascript.source_maps = true でソースマップも出せ、ブラウザのデバッガでGleamのソース行を追えます。
@externalによるJavaScript・Erlangとの連携
他言語の関数は @external 属性で型を付けて取り込みます。ターゲットごとに実装を書き分けられるので、同じ関数名で両方に対応できます。
@external(javascript, "./now_ffi.mjs", "now")
@external(erlang, "os", "system_time")
pub fn now() -> Int
pub fn main() -> Nil {
echo now() > 0
Nil
}
JavaScript側は src/now_ffi.mjs に export function now() { return Date.now(); } を置くだけです。両ターゲットで True が出ることを確認しました。ただし、この例が確かめるのは戻り値が正であることだけです。JavaScriptのDate.now()はミリ秒、Erlangのos:system_time()はnative単位なので、共通の時刻APIにする場合は単位を統一する必要があります。ただし外部関数の型は、Gleamが宣言を信じるだけで検査はしません。実装が宣言と違う型を返すと、Gleamの型安全はそこで崩れます。
JavaScriptで使えないものと数値の制約
最も影響が大きいのは、gleam_otp と gleam_erlang がErlangターゲット専用であることです。前章のactorを --target javascript でビルドすると、次のエラーで止まります。
error: Unsupported target
This value is not available as it is defined using externals, and there is
no implementation for the JavaScript target.
数値も違います。JavaScriptターゲットの Int はJavaScriptのnumber型なので、整数を安全に扱える範囲は−(2^53−1)〜2^53−1で、範囲外では整数によって丸めが発生します。9_007_199_254_740_993 を出力すると、Erlangでは 9007199254740993、JavaScriptでは警告のうえ 9007199254740992 になりました。IDや金額を大きな整数で扱うコードは、JavaScriptターゲットで動かす前に範囲を確認してください。
フロントエンド開発とLustre
ブラウザ向けのUIには、Elmと同じModel・Update・Viewの構成を取るフレームワーク Lustre(v5.7.1・2026年7月13日)がよく使われます。既存のReactアプリにGleamを混ぜるなら、ビジネスロジックをGleamで書いて .mjs と型定義を読み込む形になります。サーバー側はWebフレームワーク Wisp(v2.2.2)とHTTPサーバー Mist(v6.0.3)の組み合わせが定番です。Elm Architecture自体の考え方はElm(プログラミング言語)の解説記事で詳しく扱っています。
Elixir・Elm・OCaml・Rustとの違い
| 言語 | 実行環境 | 型 | Gleamとの主な違い |
|---|---|---|---|
| Gleam | BEAM・JS | 静的・推論 | - |
| Elixir | BEAM | 段階的(推論中心) | マクロ・Phoenix |
| Elm | JS(主にブラウザ) | 静的・推論 | ブラウザUI中心 |
| OCaml | ネイティブ・JS | 静的・推論 | ファンクタ・可変値あり |
| Rust | ネイティブ | 静的 | 所有権・トレイト |
Elixirとの違いと相互運用
同じBEAM上の言語で、最も比較されるのがElixirです。Elixirはバージョンごとに型検査の範囲を広げており、1.18で関数呼び出しの型検査、1.19でプロトコルと無名関数の型推論が加わりました。2026年6月3日公開のElixir v1.20では、型注釈なしですべての言語構文から関数定義の型を推論し、確実なバグやデッドコードを見つけるようになりました。ただし公式ドキュメントは「ユーザーが書く型シグネチャは今後のリリースで予定」としており、現時点で開発者が型に触れるのは主にコンパイラの警告と診断を通じてです。Gleamは最初から型が言語の中心で、型が合わなければビルドできません。Gleam公式FAQも「2つの型システムは可能な限り異なる」と書いています。
相互運用はできます。Gleamのビルドツールは、Elixirがインストールされていれば、Elixirの依存やソースファイルをGleamプロジェクト内でコンパイルします。ただしElixirのマクロはElixirの外から呼べないため、マクロ前提のAPIは、Elixirで薄いモジュールを書いてからGleamで呼ぶ必要があります。Elixirのパターンマッチやバイナリ処理の実例はElixirのバイナリとパターンマッチの記事が参考になります。
Elm・OCaml・Rustとの違い
Elmとは構文と「例外もnullも無い」設計思想が近い言語です。ElmはJavaScriptにコンパイルされ、ブラウザ向けUI開発が主用途です(Platform.workerを使えばNode.js上でも動かせます)。GleamはBEAMとJavaScriptを公式ターゲットとし、サーバーやCLIにも対応します。OCamlとは型推論とバリアント型が共通ですが、OCamlにはファンクタや可変の参照があり、Gleamは機能を絞る方向です。Rustとは構文が似ていても、Rustは可変性を制御する低レベルの命令型言語で、GleamはGC付きの関数型言語だと公式FAQは区別しています。型クラスを軸にした抽象化が必要なら、Haskellが得意とする分野の方が合います。
バージョン履歴と1.x系の主な変更
v1.0の告知は「セマンティックバージョニングに従い、後方互換の維持を優先する」とし、例外はセキュリティと健全性の問題だけとしています。リリース周期に決まりは無く、公式の互換性リファレンスによればマイナー版は通常1〜3か月ごと、修正が入るのは原則として最新のマイナー版だけです。
| 版 | 公開日 | 主な変更 |
|---|---|---|
| v0.1 | 2019-04-15 | 最初の公開版 |
| v1.0.0 | 2024-03-04 | 初の安定版 |
| v1.9.0 | 2025-03-09 | echoキーワード |
| v1.13.0 | 2025-10-19 | 外部向けのデータAPI |
| v1.16.0 | 2026-04-24 | JSのソースマップ |
| v1.17.0 | 2026-06-02 | gleam export escript |
| v1.18.0 | 2026-07-29 | LSPのフィールド対応・OTP 29 |
| v1.18.1 | 2026-08-01 | 現行の安定版 |
| v1.19.0-rc2 | 2026-09-26 | リリース候補 |
標準ライブラリ gleam_stdlib も2026年4月18日にv1.0.0へ到達しました。これより前のstdlib 0.x系を前提にした解説記事のコードは、io.debug のように削除済みの関数を含むことがあります。
Gleamを採用すべきでない場面
公式FAQは本番利用について「ミッションクリティカルな用途にも使える」と明言しており、公式サイトにはロンドンのマーケティング会社Strand(2024年1月から利用)や、ブラジルのマーケティング分析企業Uncover(2024年4月から利用)の事例が載っています。それでも、次の条件に当てはまるなら別の言語を選ぶ方が安全です。
- Phoenix・Ectoなどマクロ中心のElixir資産に依存している:マクロはGleamから直接呼べず、ラッパーのElixirモジュールが増える。
- ホットコードアップグレードを運用の前提にしている:差し替えは型検査されず、OTPライブラリも型安全を優先した設計。
- JavaScriptターゲットでOTPのような並行処理を期待している:
gleam_otpはErlang専用で、JS側は別の設計が要る。 - 型クラスやLisp風マクロで抽象化したい:公式FAQはこれらを追加予定のない機能として挙げている。
見落としやすい仕様として、整数の0除算は例外にならず 0 を返します。BEAMに無限大の値が無く、Gleamは暗黙の例外を投げないためです。0除算を検出したい箇所では、Result を返す標準ライブラリの関数(int.divide など)を使ってください。BEAMの軽量プロセスとOSスレッドの関係はグリーンスレッドとOSスレッドの違いの記事で扱っています。
Gleamに関するよくある質問
Gleamの読み方と名前の由来は?
「グリーム」と読みます。公式FAQによれば、Erlang VMの名前「BEAM」と韻を踏み、意味も近い英単語から取られています。英単語のgleamは「かすかな光・きらめき」です。
Gleamのインストールには何が必要ですか?
Gleam本体に加え、Erlangターゲットでの実行にはErlang/OTP、JavaScriptターゲットでの実行にはNode.jsなどのJavaScriptランタイムが必要です。macOSは brew install gleam でErlangとrebar3も入ります。Windowsは winget install --id Gleam.Gleam と winget install --id Erlang.ErlangOTP です。v1.18はOTP 29と28に対応しています。
GleamとElixirはどちらを選ぶべきですか?
型でビルド時に誤りを止めたいならGleam、Phoenixなどの成熟したフレームワークとマクロを使いたいならElixirです。同じBEAM上で動くので、Elixirがインストールされていれば、GleamのプロジェクトでElixirの依存やソースをコンパイルして呼び出せます。
GleamはReactやフロントエンド開発で使えますか?
JavaScriptターゲットでブラウザ向けのコードを出力できます。UIはElm風のフレームワークLustreで書くのが一般的です。既存のReactアプリと組み合わせるなら、React側からGleamの出力した関数を呼び出す形になります。
Gleamの最新バージョンはいくつですか?
2026年9月27日時点の安定版はv1.18.1(2026年8月1日公開)で、v1.19.0はリリース候補のrc2が出ています。最新はGitHubのgleam-lang/gleamのリリースページで確認できます。