marimo(マリモ)は、セルの実行順序に結果が左右されないPython向けノートブックです。ファイルがJSONではなく普通の.pyとして保存され、あるセルの変数を書き換えると、それを使っている下流のセルが自動で追従します。この記事では 2026年9月18日に macOS・Python 3.13.14・marimo 0.24.2 の環境で実際に動かし、インストールからUI要素、DuckDBのSQLセル、キャッシュ、Jupyterからの移行、アプリとしての公開までを実測値つきで整理します。
まとめ
- marimo のノートブックは
.pyファイルそのもので、python notebook.pyと打てばスクリプトとして走ります。実測でもmo.ui.sliderの既定値がそのまま使われて計算結果が出ました。 - セル間の依存はmarimoが解析するため、同じ変数名を2つのセルで定義するとエラーになります。
marimo checkが終了コード1でこれを検出するので、CIに載せられます。 - SQLセルの実行に必要な依存は標準インストールに入っていません。
pip install 'marimo[sql]'が必要で、mo.sqlの戻り値は Polars の DataFrame でした。 mo.cacheはプロセス内、mo.persistent_cacheはディスク。実測で 1.227秒の処理が別プロセスの2回目には 0.008秒になりました。marimo runの認証は既定で無効(--tokenの既定がno-token)です。marimo editとは逆なので、外部公開時は必ず指定します。
まずは保存形式とセルの依存関係という、Jupyterとの違いが出る土台から確認します。
marimoとは何か:Jupyterノートブックとの決定的な違い
marimo は marimo-team が Apache-2.0 で公開しているオープンソースのPythonノートブックです。GitHubのスター数は 22,819(2026-09-18時点)、PyPI の最新版は 0.24.2(2026-09-11公開)で、対応Pythonは 3.10 以上です。Jupyter との違いは見た目ではなく、ファイル形式と実行モデルの2点に集約されます。
保存形式は普通のPythonスクリプト
marimo が書き出すファイルは、セルが関数として並んだだけのPythonコードです。次はスライダーを1つ置いて合計を計算するノートブックの中身そのものです。
import marimo
__generated_with = "0.24.2"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _(mo):
n = mo.ui.slider(1, 10, value=3, label="件数")
n
return (n,)
@app.cell
def _(n):
total = sum(range(n.value + 1))
print("total =", total)
return (total,)
if __name__ == "__main__":
app.run()
関数の引数がそのセルの入力、return がそのセルの出力です。セル定義と依存関係がそのまま実行可能なPythonコードとして保存されるため、python nb.py と打つだけでスクリプトとして動きます。実行回数も出力結果もファイルには残りません。実際に実行すると、スライダーの既定値 3 が使われて total = 6 と出力されました。UI部品を含んだノートブックが、そのままバッチ処理として使えます。
Git差分に出る行数の実測比較
ipynb は実行結果と実行時刻をファイルに書き戻します。今回 nbclient で実行したノートブックをコミットし、threshold = 10 を 12 に変えて再実行したところ、git diff --numstat は14行の変更を報告しました。意味のある変更は2行(ソースの該当行と出力値)だけで、残る12行は iopub.execute_input や shell.execute_reply といったセルの実行時刻メタデータでした。
同じ変更を marimo の .py で行うと、差分は該当の1行だけです。レビューやコンフリクト解消の手間に直結します。
インストールとCLIの全体像
導入は pip か uv で1行です。Pythonのバージョン管理を分けている場合は、marimo を入れる環境が 3.10 以上であることを先に確認してください(pyenvでPythonのバージョンを切り替える手順|shimの仕組みとビルド失敗の対処も参考になります)。
# pip の場合
pip install marimo
# uv の場合(作成・有効化済みの仮想環境で実行)
uv pip install marimo
# 動作確認
marimo --version # => 0.24.2
# 新規ノートブックを作ってブラウザエディタを開く
marimo edit notebook.py
# チュートリアル
marimo tutorial intro
用途別に分かれた6つのextras
marimo は必要な機能だけを足す設計で、PyPIのメタデータ上 lsp・mcp・otel・recommended・sandbox・sql の6つのextraがあります。素の pip install marimo では SQLセルもipynb書き出しも動きません。
| やりたいこと | 必要な追加導入 | 入るもの |
|---|---|---|
| SQLセルを使う | pip install 'marimo[sql]' |
duckdb 1.0.0以上・polars[pyarrow] 1.9.0以上・sqlglot[c] 26.8.0以上 |
| ipynbへ書き出す | pip install nbformat |
nbformat(本体に同梱されていない) |
| 分離環境で動かす | pip install 'marimo[sandbox]' |
uv 0.9.21以上・pyzmq 27.1.0以上 |
| 補完・ruff連携 | pip install 'marimo[lsp]' |
python-lsp-server 1.13.0以上・python-lsp-ruff 2.0.0以上 |
| まとめて入れる | pip install 'marimo[recommended]' |
上記に加え altair・ruff・nbformat・cryptography など |
ipynb書き出しを未導入のまま実行すると「nbformat is required to convert marimo notebooks to ipynb.」と表示されて止まります。判断に迷うなら recommended で一括導入し、必要最小限に絞りたい場合だけ個別のextraを指定してください。
12個のCLIコマンドと使い分け
marimo --help が出すトップレベルコマンドは次の12個です。日常的に使うのは edit・run・convert・export・check の5つです。
| コマンド | 用途 |
|---|---|
marimo edit |
ブラウザエディタで作成・編集 |
marimo run |
読み取り専用のアプリとして起動 |
marimo convert |
ipynb・Markdown・py:percent形式からの変換 |
marimo export |
html・html-wasm・ipynb・md・pdf・script・session・thumbnail へ書き出し |
marimo check |
静的チェックと整形 |
marimo new |
空のノートブック生成 |
marimo config |
設定の表示・説明 |
marimo env |
環境情報の出力 |
marimo pair |
AIとのペアプログラミング |
marimo recover |
JSONからの復旧 |
marimo tutorial |
チュートリアルを開く |
marimo shell-completion |
シェル補完の導入 |
UI要素と依存セルの自動再計算
marimo の mo.ui には 37個の要素が用意されています(0.24.2 で dir(mo.ui) を数えた実測値)。スライダーやドロップダウンを置くと、値が変わった瞬間にその値を参照しているセルだけが再計算されます。コールバックを書く必要はありません。
| 分類 | 主な要素 |
|---|---|
| 数値・範囲 | slider・range_slider・number |
| 選択 | dropdown・multiselect・radio・checkbox・switch |
| 文字・コード | text・text_area・code_editor |
| データ | table・dataframe・data_editor・data_explorer・file・file_browser |
| グラフ | altair_chart・plotly・matplotlib・anywidget |
| 操作 | button・run_button・form・refresh・batch |
グラフ描画は既存のライブラリをそのまま使えます。Plotly を組み合わせる場合の色指定はPlotlyの色(color)指定と使い方|Express・React・画像出力まで【v6対応】にまとめています。
再計算のタイミング制御(formとmo.stop)
テキスト入力の mo.ui.text は debounce の既定値が True で、Enterキーを押すかフォーカスが外れた時点で値が確定します。debounce=False を指定すると1文字ごとに下流が走るので、重い処理につなぐ場合は既定のままにしてください。複数の入力をまとめて1回で確定させたいときは .form() を使います。送信ボタンを押すまで値が確定しません。
import marimo as mo
# 送信ボタンを押したときだけ値が確定する
query = mo.ui.text(label="検索語").form()
query
# 値が未入力のあいだは下流のセルを止める
mo.stop(query.value is None, mo.md("検索語を入力してください"))
hits = [n for n in ("東京", "大阪", "福岡") if query.value in n]
hits
mo.stop(predicate, output) は第1引数が真のときにそのセルの実行を打ち切り、第2引数を出力として表示します。重いクエリやAPI呼び出しの前に置いておくと、初期表示でいきなり走るのを避けられます。
DuckDBを使うSQLセルの書き方
marimo は mo.sql() でSQLを書けますが、実行にはDuckDBなどの追加依存が必要で、標準インストールには入っていません。素の pip install marimo の環境で実行したところ、ManyModulesNotFoundError: The following packages are required to execute sql: sqlglot で停止しました。pip install 'marimo[sql]' を入れると動きます。
import marimo as mo
import polars as pl
sales = pl.DataFrame({
"店舗": ["東京", "大阪", "東京", "福岡"],
"金額": [120, 340, 80, 560],
})
top = mo.sql(
f"""
SELECT 店舗, SUM(金額) AS 合計
FROM sales
GROUP BY 店舗
ORDER BY 合計 DESC
"""
)
このコードはmarimoのノートブック内のセルとして実行します。Pythonの変数名をそのままテーブル名にできるのがポイントで、sales という DataFrame が FROM sales で引かれ、福岡560・大阪340・東京200が返りました。戻り値は polars.dataframe.frame.DataFrame で pandas ではないため、そのまま次のセルで Polars の処理につなげられます。
裏で動いているのは DuckDB なので、CSVやParquetを直接クエリする書き方もそのまま使えます。DuckDB側の詳しい使い方はDuckDBの使い方:インストールからPython・CLI・ファイル読み込みまでの実装手順、戻り値のPolarsについてはPolarsとは?pandasとの違い・高速化の仕組みと実務での採用判断【実装目線】を参照してください。
重い処理を抑える2種類のキャッシュ
リアクティブ実行は便利な一方、上流を触るたびに重い処理が走ります。marimo にはこれを抑える仕組みが2種類あり、寿命が違います。
mo.cache=プロセス内だけのメモリ保存
@mo.cache は、関数の引数だけでなくクロージャで参照している変数とノートブックのコードもキーに含めてメモリへ保存します。引数はハッシュ可能である必要がなく、pickle化できればリストやNumPy配列でも使えます。0.5秒かかる関数を2回呼ぶ実測では、1回目 0.501秒に対し2回目は 0.000426秒でした。ただし同じスクリプトを別プロセスとして起動し直すと再び 0.647秒かかり、キャッシュは残っていません。
import marimo as mo
import time
@mo.cache
def slow(n):
time.sleep(0.5)
return n * n
mo.persistent_cache=ディスクに残る保存
プロセスをまたいで残したい場合は mo.persistent_cache を使います。こちらは with ブロックで囲んだ範囲の変数をまとめて保存します。1秒スリープする処理を含むブロックの実測は、1回目 1.227秒、いったんプロセスを終了してから実行した2回目が 0.008秒でした。
import marimo as mo
import time
with mo.persistent_cache(name="demo"):
time.sleep(1.0)
heavy = sum(range(10**6))
保存先はノートブックと同じ階層の __marimo__/cache/demo/ で、既定では pickle として書き出されます。生成物なので .gitignore に __marimo__/ を足しておくのが無難です。
Jupyterノートブックからの移行手順
既存の .ipynb は marimo convert で変換できます。対応入力は ipynb のほか、{python} フェンスを含むMarkdown、py:percent形式の .py スクリプトです。
marimo convert legacy.ipynb -o legacy.py
ipynb変換で起きるセル構造の変化
Markdownセルは mo.md() を呼ぶセルに変わり、コードを畳む @app.cell(hide_code=True) が付きます。ipynb 側の出力は捨てられます。依存関係はmarimoが解析し直すため、セルの引数として明示されます。実測では、statistics と sales を別セルで定義したノートを変換すると、それを使うセルが def _(sales, statistics): という形になりました。元のipynbの execution_count は逆順でしたが、出力は正しい依存順です。
移行の最初の壁=セル間の変数名重複
marimo では同じ名前の変数を複数のセルで定義できません。df を使い回す書き方は、Jupyter では普通でも marimo では通りません。marimo check にかけると次のように出ます。
critical[multiple-definitions]: Variable 'df' is defined in multiple cells
--> dup.py:8:1
8 | def _():
9 | df = 1
| ^
10 | return (df,)
...
14 | def _():
15 | df = 2
| ^
16 | return (df,)
hint: Variables must be unique across cells. Alternatively, they can be
private with an underscore prefix (i.e. `_df`.)
ヒントにあるとおり、セル内でしか使わない一時変数はアンダースコア始まりにすれば重複が許されます。これを直さずに実行すると、実行時に marimo._ast.errors.MultipleDefinitionError で止まります。循環参照も同様に cycle-dependencies として検出されます。
marimo check は上記のようなエラーがあるとき終了コード1、何も無ければ0を返すので、そのままCIに入れられます。警告どまりの指摘は既定では0のままなので、警告も失敗扱いにしたい場合は --strict を付けます。--format json を付けると "code": "MB002" のような規則コードつきのJSONが出るため、結果を機械処理したい場合はこちらが扱いやすい選択です。自動修正は --fix です。
ローカルモジュールの検索パスと自動リロード
ノートブックから自作モジュールを import したい場合は、pyproject.toml にプロジェクト設定を書きます。実測では相対パスが絶対パスへ解決され、プロジェクト設定として読み込まれました。
[tool.marimo.runtime]
pythonpath = ["libs"]
auto_reload = "autorun"
auto_reload の既定値は off で、取りうる値は off・lazy・autorun の3つです。既定のままだとモジュール側を編集してもノートブックに反映されません。lazy は変更を検知したセルを再実行待ちの状態にし、autorun は自動で走らせます。モジュールを書きながらノートブックで確かめる作業では autorun が便利です。
アプリとして配る:marimo runとWASM書き出し
作ったノートブックはそのままWebアプリになります。marimo run notebook.py でサーバが立ち、コードが見えない読み取り専用の画面が出ます。Streamlit のように別途アプリ用のコードを書き直す必要はありません(Streamlit 側の考え方はStreamlitとは?できること・使い方・料金を実例コードで解説【Python】にまとめています)。
公開前に確認すべき4つの既定値
CLIヘルプで確認した既定値には、そのまま外部公開すると問題になるものがあります。
| オプション | marimo run の既定 |
意味 |
|---|---|---|
--host |
127.0.0.1 | 外部から届かせるには明示指定が必要 |
--token |
no-token | 認証なし(marimo edit は token が既定で逆) |
--include-code |
無効 | 既定ではソースがブラウザへ送られない |
--headless |
無効 | サーバ用途では付けてブラウザ起動を抑止 |
特に注意したいのが認証です。marimo edit はトークン認証が既定で有効ですが、marimo run は既定で無効になっています。つまり marimo run app.py --host 0.0.0.0 とだけ打つと、そのポートに到達できる相手は誰でも操作できます。社内向けであっても --token-password-file でトークンを与えるか、リバースプロキシ側で認証をかけてください。プロキシ配下に置く場合は --base-url と --proxy が用意されています。
marimo run app.py --host 0.0.0.0 --port 8080 --headless \
--token-password-file /run/secrets/marimo_token
サーバを立てずに配るWASM書き出し
marimo export html-wasm は、ブラウザ内のPythonで動く静的サイトを吐きます。GitHub Pages 用の .nojekyll も同梱されるため、静的ホスティングにそのまま置けます。ブラウザでPythonやSQLを動かす仕組みはDuckDB WASMとは?ブラウザでSQL分析を実行する仕組みと実装・採用判断でも扱っています。
marimo export html-wasm notebook.py -o site --mode run
python -m http.server --directory site
実測では出力ディレクトリが約27MBになりました。内訳はプロット描画やSQLパーサなどmarimoのフロントエンド資産で、Python実行系のPyodide本体は同梱されず cdn.jsdelivr.net から読み込まれます。つまり27MBは自分で配置するファイルの量であって、閲覧時の通信量そのものではありません。もう1点、--mode run かつ --show-code を付けない既定でも、生成された index.html の中には notebookCode という項目としてノートブック全文が埋め込まれていました。ブラウザ側で実行する以上コードを送らざるを得ないためで、--show-code は表示するかどうかを切り替えるだけです。コードを見せたくない場合にWASM書き出しは使えません。その用途では、ソースを送らない marimo run を選びます。
依存ごと固定する--sandboxの挙動
--sandbox はノートブック冒頭のPEP 723インラインメタデータを読み、uv で隔離環境を作ってから実行します。手元の環境には polars 1.44.2 が入っている状態で、次のヘッダを持つノートブックを --sandbox 付きで実行したところ、uv run --isolated --no-project が起動し、出力は「polars 1.33.1」でした。ヘッダでの固定が実際に効いています。
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "marimo",
# "polars==1.33.1",
# ]
# ///
ノートブックと依存関係が1ファイルに収まるため、配布先に環境構築の手順書が要りません。利用には uv の導入が前提です。
設定ファイルとエディタ連携
設定は2階層です。ユーザ全体の設定は ~/.config/marimo/marimo.toml、プロジェクト固有の設定は pyproject.toml の [tool.marimo.*] に書きます。実測では両方が読まれ、marimo config show の出力に「Project overrides」と「User config」として別々に表示されました。チームで揃えたい設定はリポジトリに入る pyproject.toml 側へ置きます。
エディタは公式のVS Code拡張 marimo-team.vscode-marimo が用意されています。2026-09-18時点のバージョンは 0.17.3、インストール数は 68,257件でした。リンタ連携は [tool.marimo.language_servers.pylsp] 配下で切り替え、ruff や mypy の有効・無効を個別に指定できます。
よくある質問
marimoのインストールにPythonのバージョン制約はありますか?
あります。PyPI上のメタデータでは 0.24.2 の requires_python が 3.10 以上です。Python 3.9 の仮想環境で pip install marimo を実行したところ、エラーは出ずに 0.17.6 が入りました。エラーで気づけないので、導入後に marimo --version で確認してください。
marimoのノートブックはJupyterに戻せますか?
marimo export ipynb notebook.py -o notebook.ipynb で戻せます。ただし nbformat が別途必要で、未導入だと「nbformat is required to convert marimo notebooks to ipynb.」と表示されて失敗します。
同じ変数名を複数のセルで使えないのは不便ではありませんか?
セル内で閉じる一時変数はアンダースコア始まりにすれば重複が許されます。_df のように書けば、別のセルで同じ名前を使えます。共有したい変数だけを通常の名前にする、という切り分けになります。
marimo runで公開したアプリからコードは見えますか?
既定では見えません。--include-code は既定で無効で、ヘルプにも既定ではコードがクライアントへ送られないと明記されています。ただし marimo export html-wasm で書き出した静的サイトは別で、index.html の中にノートブック全文が埋め込まれます。
marimoのバージョンはどの程度の頻度で上がりますか?
PyPIには 0.24.2 時点で 390版が公開されており、直近も 0.24.0 が 2026-08-17、0.24.2 が 2026-09-11 と月に複数回のペースです。0.x系なので、チームで使うなら pyproject.toml や PEP 723 ヘッダで版を固定しておくと安全です。