受託でも自社開発でも、外部の SaaS とつなぐ処理を書くたびに同じことを繰り返します。認可画面を出し、返ってきたトークンを暗号化して保存し、期限が切れる前に更新し、API の呼び出し回数の上限に当たったら待って再試行する。中身の処理より、この周辺のほうが手間も事故も多い。
Nango は、その周辺を丸ごと引き受ける連携基盤です。1,000 を超える API の認可とトークン管理、利用者ごとの API 呼び出しの中継、TypeScript で書いた同期処理の実行までを担います。この記事は、GitHub のリポジトリから手元の Mac に Docker で立ち上げ、GitHub をつないで実際にデータを取り、処理を 1 本書いて動かすところまでを記録したものです。検証日は 2026 年 9 月 14 日、サーバーは 0.71.7、対象コミットは 8ed88bc です。
読み手として想定しているのは、freee、kintone、Slack、Google Workspace との連携を何度も作ってきた開発者と、その工数を減らしたい会社の担当者です。API そのものの考え方はAI エージェント時代の API の記事に、ワークフロー型の自動化ツールとの比較はn8n と Zapier と Make の比較記事にあります。
Nango は Docker で 17 秒で立ち上がり、既存のアクセストークンを取り込む経路なら、ブラウザでの OAuth アプリ登録なしに GitHub のデータを取れた。TypeScript で書いた処理はローカルの dryrun で動いたが、無料のセルフホストでは deploy が通らない。無料で使えるのは認可の保管と API の中継までで、定期同期や Webhook は有料版が要る。対応 API は 1,007 件で kintone と Slack と Google Drive はあるが freee はない。ライセンスは Elastic License 2.0 で、自社製品の中で使うのは問題ないが、連携基盤そのものを他社に売ることはできない。
この記事の要約
Nango とは何か
README は 3 つの部品で説明しています。Auth は、1,000 以上の API について OAuth の画面遷移、API キーの保管、トークンの自動更新を代行し、自社アプリに埋め込める認可画面(Connect UI)も付きます。Proxy は、保管した資格情報を使って利用者ごとに外部 API を呼び、再試行と呼び出し回数の上限の扱いを含みます。Functions は、TypeScript で書いた同期処理と実行処理を Nango 側の実行環境で動かします。
自社で持たずに済むのは、利用者ごとのトークンをどこにどう暗号化して置き、いつ更新するか、という部分です。README は本番採用企業として Replit、Ramp、Mercor を挙げています。提供形態は、クラウド版と、機能を絞った無料のセルフホスト版、全機能のエンタープライズ向けセルフホスト版の 3 つです。
ドキュメントは対応 API を 1,000 以上と書いていますが、リポジトリ内の定義ファイルを数えると 1,007 件でした。認証方式の内訳も同じファイルから機械的に数えられます。1,007 件のうち 945 件に方式の記載があり、残り 62 件は他の定義を引き継ぐ別名です。
| 認証方式 | 件数 | 意味 |
|---|---|---|
| API_KEY | 329 | API キーを渡すだけ。OAuth の画面遷移がない |
| OAUTH2 | 302 | 利用者が認可画面で許可する方式。Slack や Google など |
| OAUTH2_CC | 103 | OAuth 2.0 のクライアント資格情報方式。サーバー間 |
| BASIC | 98 | ID とパスワード |
| TWO_STEP | 65 | 2 段階でトークンを得る独自方式 |
| MCP_OAUTH2 | 28 | MCP サーバー向けの OAuth |
| その他の方式 | 20 | OAUTH1 4、JWT 4、NONE 2 など 11 種 |
| 方式の記載なし | 62 | 他の定義を引き継ぐ別名(Google カレンダーなど)が中心 |
API キー方式が最多で、OAuth を使わずにつなげる相手のほうが数の上では多い。日本の SaaS の収録状況は、記事の後半で扱います。
セルフホストは 17 秒で立ち上がる。ただしドキュメントの手順は使えない
公式のセルフホストの案内は、docker-compose.yaml を wget で取得して docker compose up するだけ、と書いています。これは今の compose ファイルとかみ合っていません。取得したファイルには、対応 API の定義ファイル(packages/providers/providers.yaml)をコンテナに割り当てる記述があり、wget しただけのディレクトリにはそのファイルが存在しないからです。割り当て元のファイルが存在しないことは docker compose config と ls で確認しました。この状態で起動すると Docker は割り当て先に空のディレクトリを作るため、対応 API の定義が読めません(起動そのものは今回試していません)。
したがって、リポジトリごと clone するのが正解です。clone は 15.7 秒、取得後の容量は 495 MB、イメージ取得込みの初回起動は 16.6 秒でした。回線とキャッシュの状況で変わります。
git clone --depth 1 https://github.com/NangoHQ/nango.git repo
cd repo
cp .env.example .env # NANGO_ENCRYPTION_KEY などを設定
docker compose -p nango up -d
curl -s http://localhost:3003/health
# {"result":"ok"}今回の Mac では PostgreSQL の 5432 番と Redis の 6379 番が別のコンテナで使用中だったため、上書き用の compose ファイルで別の番号に逃がしました。同時に、既定では無効になっているログの保管(Elasticsearch)を有効にしています。イメージの容量は、Nango 本体が 1.4 GB、Elasticsearch が 1.26 GB、PostgreSQL が 348 MB、Redis が 198 MB の合計約 3.2 GB です。Elasticsearch を使わなければ約 2.0 GB で済みます。

起動でつまずいたのは 3 か所です。1 つ目、前回の試行で起動途中のコンテナを落としていたため、データベースのマイグレーション(構造の更新処理)のロック行が残り、起動を繰り返す状態になりました。データベースを作り直さずに、ロック表の該当行を 0 に戻すと直ります。ロック表は 3 つのスキーマに分かれているので、直前のログでどれか特定します。
docker exec nango-db psql -U nango -d nango
-c "UPDATE nango_records.migrations_lock SET is_locked = 0;"
docker compose -p nango restart nango-server2 つ目、環境変数 SERVER_PORT を書かないと 3003 番で待ち受けません。compose のポート公開は既定値 3003 が効くのに、コンテナ内のサーバーは環境変数が空だと 8080 番で起動します。既定値の食い違いで、3003 番へ接続してもエラーメッセージが出ないまま応答がありません。起動ログの listening on port 8080 を見ないと気づけません。.env.example を写して使えば踏みません。3 つ目、ログを有効にする設定だけでは起動せず、Elasticsearch のユーザー名とパスワードの環境変数が、値は空でよいのですが、キー自体が無いと起動しません。
ブラウザなしで GitHub をつなぎ、データを取る
通常の経路では、相手先の開発者コンソールで OAuth アプリを登録し、そのクライアント ID とシークレットを Nango に入れて、利用者に認可画面で許可してもらいます。今回はその手順を避け、認可の案内にある「手持ちの資格情報で API から接続を作る」経路を使いました。GitHub の CLI が持っているアクセストークンを、そのまま Nango に取り込みます。
最初に環境のシークレットキーが要ります。管理画面の設定ページには表示されず、管理画面の API から取ります。既定で全権限のキーが 1 本作られています。次に連携先(integration)を作ります。GitHub の定義は OAuth 2.0 なので、クライアント ID とシークレットの入力が必須ですが、トークンを直接取り込む今回の経路では使われないため、仮の値を入れました。
curl -s -X POST http://localhost:3003/integrations
-H "Authorization: Bearer $NANGO_SECRET_KEY" -H 'Content-Type: application/json'
-d '{"provider":"github","unique_key":"github-pat","display_name":"GitHub (PAT import)",
"credentials":{"type":"OAUTH2","client_id":"unused-placeholder",
"client_secret":"unused-placeholder","scopes":"repo,read:user"}}'
GH=$(gh auth token)
curl -s -X POST http://localhost:3003/connections
-H "Authorization: Bearer $NANGO_SECRET_KEY" -H 'Content-Type: application/json'
-d "{"provider_config_key":"github-pat","connection_id":"koji-github",
"credentials":{"type":"OAUTH2","access_token":"$GH"},
"end_user":{"id":"koji","email":"koji@example.com","display_name":"Koji"}}"接続ができたら、Proxyで外部 API を呼びます。呼び出し側は api.github.com を知りません。接続 ID と連携先 ID だけを渡し、トークンはサーバー側で解決されます。これが Proxy の要点です。
curl -s "http://localhost:3003/proxy/user/repos?per_page=3&sort=updated"
-H "Authorization: Bearer $NANGO_SECRET_KEY"
-H "Connection-Id: koji-github" -H "Provider-Config-Key: github-pat"
# [{"full_name":"...","private":true,"updated_at":"2026-09-14T22:24:52Z"}, ...]

なお、Nango が用意した共用の OAuth アプリを使う quickstart の経路は、セルフホストでは使えません。API が「この provider には Nango 提供の開発者アプリが設定されていない」と返します。通常の経路で必要になる作業は、相手先で OAuth アプリを登録し、コールバック URL に Nango のもの(今回の構成なら localhost:3003/oauth/callback)を登録し、発行されたクライアント ID とシークレットを連携先に入れ、接続作成の APIかセッションを作って利用者に認可画面で許可してもらう、の 4 段階です。kintone だけは接続時にサブドメインの指定が要ります。
TypeScript で処理を書き、dryrun で動かす
CLIで雛形を作り、処理を 1 本足しました。雛形は GitHub 用の同期処理、実行処理、イベント処理が 1 本ずつ入ります。今回書いたのは、つないだ GitHub の利用者が見られるリポジトリを新しい順に返す実行処理(action)です。連携先 ID と同じ名前のディレクトリに置きます。
import { createAction } from 'nango';
import * as z from 'zod';
const repoSchema = z.object({
full_name: z.string(), private: z.boolean(), stars: z.number(), updated_at: z.string()
});
const action = createAction({
description: 'List the repositories the connected GitHub user can see (newest first).',
version: '1.0.0',
endpoint: { method: 'GET', path: '/github-pat/repos', group: 'Repos' },
input: z.object({ per_page: z.number().default(5) }),
output: z.object({ count: z.number(), repos: z.array(repoSchema) }),
exec: async (nango, input) => {
const res = await nango.proxy<any[]>({
method: 'GET', endpoint: '/user/repos',
params: { per_page: String(input.per_page), sort: 'updated' }
});
const repos = res.data.map((r) => ({
full_name: r.full_name, private: r.private, stars: r.stargazers_count, updated_at: r.updated_at
}));
await nango.log(`Fetched ${repos.length} repositories`);
return { count: repos.length, repos };
}
});
export default action;export NODENV_VERSION=22.18.0
npm install nango@latest
./node_modules/.bin/nango init proj --auto-confirm
./node_modules/.bin/nango dryrun listRepos koji-github
--integration-id github-pat --input '{"per_page":5}'
-e dev --no-interactive --auto-confirm
# ✓ Typechecking
# ✓ Compiled
# http [200] GET http://localhost:3003/proxy/user/repos?per_page=5&sort=updated
# Fetched 5 repositories
# { "count": 5, "repos": [ ... ] }dryrun は --auto-confirm だけでは環境選択の質問で止まります。-e dev と --no-interactive を付けます。ここまでは無料のセルフホストで問題なく動きました。

deploy は無料セルフホストでは通らない
dryrun は動きますが、nango deploy は失敗します。処理の実体を S3 に置きに行き、AWS の資格情報がないので落ちます。無料セルフホストの構成には S3 の設定が含まれていません。公式の「無料セルフホストは Auth と Proxy のみ」という記載と符合します。
./node_modules/.bin/nango deploy dev --auto-confirm --no-interactive
# ✗ Deploying 1 functions
# Error deploying:
# Error uploading file. Please contact support with the filename and connection details (file_upload_error)
#
# サーバー側のログ
# error (err) Could not load credentials from any providers { err: { CredentialsProviderError: ... } }要点はここです。無料セルフホストで使えるのは、認可の保管と Proxy 経由の API 呼び出しまで。定期同期、Webhook、MCP サーバーはクラウド版かエンタープライズ版のセルフホストが要ります。「書いて試す」ところまでは無料でできて、「定期実行させる」ところから有料になる、と理解するのが正確です。
もう 1 つ、雛形の github ディレクトリを消さずに deploy すると、その前に別のエラーで止まります。ディレクトリ名が、管理画面に登録した連携先 ID と一致していないと通りません。
日本の SaaS はどこまで入っているか
当社が受託と自社開発で繰り返し作っている連携先を、定義ファイルで直接検索しました。公式のカタログでも同じことが確認できます。
| サービス | 収録 | 認証方式 | 備考 |
|---|---|---|---|
| freee | なし | 会計、人事労務とも未収録。検索結果は 0 件 | |
| kintone | あり | OAuth 2.0 | 接続時にサブドメインを指定する(個別ページ) |
| Slack | あり | OAuth 2.0 | |
| Google Drive | あり | OAuth 2.0 | Google 共通の定義を継承する |
| GitHub | あり | OAuth 2.0、GitHub App | 個人アクセストークン専用の定義はない。今回は OAuth 2.0 の定義にトークンを取り込んだ |
freee をつなぐなら、自分で定義ファイルに追加して本家に提案するか、自分のフォークで持つことになります。ここは正直に書いておくべき落差です。国内の会計 SaaS を軸にした連携が主目的なら、Nango を入れる前に、この定義を誰が書いて誰が保守するかを先に決めます。SaaS に振り回されない働き方の記事で書いたツール横断の考え方は、この定義があって初めて成り立ちます。
ライセンスと料金
ライセンスは Elastic License 2.0 で、OSI が承認したオープンソースライセンスではありません。本文から、実務で効く制限は 3 つです。
| 制限 | 実務での意味 |
|---|---|
| ホスティング提供の禁止 | Nango を載せた連携基盤を、他社向けのサービスとして提供できない。自社製品の中で使うのは問題ない |
| ライセンスキー機構の迂回禁止 | 有料機能の鍵を外して使うことはできない |
| 表示の削除禁止 | 著作権表示を消せない。改変した場合はその旨を明示する義務は別条項(Notices)にある |
違反すると許諾が自動的に終了します。通知から 30 日以内に是正すれば遡って復活しますが、再度違反した場合は永久に終了します。判断の目安は、自社の製品が外部 SaaS とつながるために使うなら問題なく、連携基盤そのものを他社に売るならライセンス違反になり得る、です。
クラウド版の料金は公式の料金ページの記載です。金額は 2026 年 9 月 14 日時点で、いずれも米ドルです。
| プラン | 月額 | 含まれるもの |
|---|---|---|
| Free | 0 ドル | 接続 10 件、実行時間 10 時間、転送 10 GB。認証、事前構築済みの連携部品、Webhook、UI 部品、ホワイトラベル、ログ。SOC 2 Type II |
| Pay-as-you-go | 50 ドル(クレジットとして消費) | 環境無制限、権限管理、ログの外部出力、SAML SSO。従量は接続 0.29 ドル、実行時間 1 時間あたり 0.72 ドル、転送 1 GB あたり 0.5 ドル |
| Growth(追加) | 450 ドル | 新規 API の対応 5 営業日。専用の Slack Connect チャンネルは Pay-as-you-go 以上に付く |
| Enterprise | 個別見積 | 自社クラウドでのセルフホスト、HIPAA、SLA、専任のソリューションエンジニア。規模によっては接続 1 件あたり月 0.01 ドルまで下がる |
無料セルフホストは、接続 10 件のような数量の制限ではなく、機能そのものが Auth と Proxy に限られます。比較するなら、接続 10 件だが全機能が使えるクラウドの Free との二択です。連携の費用を先に見積もる考え方はAI コスト爆発とデータ統合の記事に書きました。
詰まりどころの一覧
wget の件を除き、すべて実機で踏んだものです。
| 事象 | 原因 | 対処 |
|---|---|---|
| wget だけで起動すると対応 API の定義が読めない | compose がリポジトリ内のファイルを割り当てる前提。wget ではそのファイルが取れない | リポジトリを clone して、その中で docker compose up する |
| 3003 番に接続できない | SERVER_PORT が空だとコンテナ内のサーバーは 8080 番で起動する | .env.example を写して SERVER_PORT=3003 を明示する |
| Migration table is already locked で起動を繰り返す | 起動途中でコンテナを落とし、ロック行が残った | ロック表の該当行を 0 に戻して再起動する。ロック表はスキーマごとに 3 つ |
| ログ画面が Logs not configured のまま | Elasticsearch が compose でコメントアウトされている。有効化しても認証情報のキーが必須 | Elasticsearch を足し、NANGO_LOGS_ES_USER と NANGO_LOGS_ES_PWD を空の値で書く。容量が約 1.2 GB 増える |
| nango deploy が file_upload_error で止まる | 処理の実体を S3 に置く構成で、無料セルフホストにはその設定がない | dryrun で動作確認まで。定期実行はクラウド版かエンタープライズ版 |
| ドキュメントの URL が 404 | docs.nango.dev から nango.dev/docs へ移転し、転送先も一部 404 | 全ページの索引 llms.txt で正しい URL を引く |
自前実装と比べて、どこで得をするか
得をするのは、つなぐ相手が多く、利用者ごとにトークンを持つ場合です。自社製品の利用者それぞれが自分の Slack や Google Drive をつなぐ、という形なら、認可画面、トークンの暗号化保存、期限切れ前の更新、呼び出し回数の上限の扱いを Nango に任せられます。利用者数が数十を超えたあたりから、自前で持つコストとの差が出ます。MCP 経由でつなぐ道具との使い分けはClaude の MCP コネクタの記事で整理しています。
得をしないのは、つなぐ相手が 1〜2 種類で、トークンが会社に 1 本しかない場合です。社内の kintone と Slack を会社のアカウントでつなぐだけなら、Nango のサーバーを 1 台運用する手間のほうが大きい。その用途なら、ワークフロー型の自動化ツールのほうが向きます。
運用の負荷は、PostgreSQL、Redis、必要なら Elasticsearch を自社で持つ、という点に集約されます。n8n を VPS でセルフホストした記事と同じ考え方で、バックアップと更新の手順を先に決めてから入れます。今回の検証で確かめられなかったのは、ブラウザでの OAuth 認可の実際の画面遷移、定期同期の実運用、トークンの自動更新(取り込んだトークンに期限がなく更新が走らないため)、クラウド版の挙動、freee 連携の 5 つです。
導入を検討するなら、この順番で
- つなぐ相手を書き出し、定義ファイルにあるか、認証方式は何かを確認する。freee のように無い相手があれば、定義を誰が書くかを決める
- 利用者ごとにトークンを持つか、会社に 1 本かを決める。1 本ならワークフロー型のツールも候補に入れる
- リポジトリを clone してセルフホストを立ち上げ、手持ちのトークンを取り込んで Proxy でデータが取れるところまで確かめる
- 処理を 1 本書いて dryrun で動かす。ここまでは無料
- 定期実行が要るなら、クラウドの Free(接続 10 件)で試し、費用は接続数と実行時間から見積もる
- 他社にサービスとして提供する形になっていないか、ライセンスの 3 つの制限と照らす
手元に残ったのは、起動手順と 3 つの落とし穴、トークンを取り込む経路のコマンド、dryrun で動いた処理 1 本、そして deploy が通らない理由です。クラウドの Free で定期同期を回した時点で、続報を書きます。
FDE を募集しています(会計FDE/FDE・業務システム)
経理の月次をAIで本番まで持っていく「会計FDE」(会計士・経理責任者・管理部門経験者)と、要件が固まる前に動くものを出して本番まで運ぶ「FDE(業務システム)」(ITコンサル・PM/PL・情シス出身者)を正社員で募集しています。応募でなくても構いません。まず30分の「キャリア相談」から。採用のお問い合わせフォームに「キャリア相談希望」と書いて送ってください。
freee・kintone・Slack との連携を、毎回ゼロから作るのをやめませんか
連携基盤を入れるか、ワークフロー型のツールで済ませるか、自前で持つかは、つなぐ相手の数と、トークンを誰が持つかで決まります。経理AX・kintone・案件管理システムの刷新で本番稼働まで伴走した経験をもとに、いまの連携の一覧を書き出すところから始められます。