結論

Blobとは「中身の形式を決めつけない、ひとかたまりのバイナリデータ」のことです。JavaScript の Blob オブジェクト、blob: で始まる Blob URL、データベースの BLOB 型、Azure Blob Storage は、どれも「画像でも PDF でも何でも、バイトの列として丸ごと扱う」という同じ考え方です。

この記事でわかること

  • Blob の4つの意味(JavaScript・Blob URL・DB の型・クラウド)の使い分け
  • Chromium で動かした new Blob → createObjectURL → 画像表示・ダウンロード・解放の実物と、解放し忘れで 455MB 増えた実測
  • SQLite・PostgreSQL(bytea)・MariaDB の BLOB 型に画像を入れて取り出した実物と、「ファイルは DB に入れるか」の判断表

2026年10月29日更新|Chromium 153・Node.js 22・SQLite 3.53・PostgreSQL 16・MariaDB 10.11 で実行確認

「blob」は英語で「かたまり・しずく」を指す言葉で、IT では Binary Large OBject(大きなバイナリの対象物)の略としても使われます。どの文脈でも共通するのは、「中身が何かは問わず、バイトの列をひとかたまりとして保存・受け渡しする」という役割です。JavaScript では、その塊に blob: で始まる仮の URL を付けて、画像の表示やダウンロードに使います。

flowchart TD
    S["文字列・ArrayBuffer・File<br>fetch の応答・canvas"] --> B["Blob<br>size と type を持つ塊"]
    B --> T["text / arrayBuffer<br>中身を読む"]
    B --> U["URL.createObjectURL<br>blob: の仮の URL"]
    U --> I["img.src・a[download]"]
    I --> R["URL.revokeObjectURL<br>使い終わったら解放"]

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
blobとは 形式を決めつけないバイナリの塊。JS・URL・DB・クラウドで同じ考え方 Blobとは(意味の使い分け)
JavaScript の Blob とは new Blob([中身], {type}) で作る、size と type を持つ読み取り専用の塊 JavaScriptのBlobとは
blob url とは URL.createObjectURL(blob) が返す blob:http://…/UUID。ページを閉じると無効 Blob URLの寿命
Blob と File の違い File は Blob に name と lastModified を足したもの BlobとFile・ArrayBuffer・Base64の違い
Blob を Base64 にする FileReader.readAsDataURL。大きさは 1.33 倍になる BlobとBase64の大きさ・速さ
revokeObjectURL は必要か 必要。4MB×100 個で 455MB 増え、解放すると 56MB まで戻った 解放しないとメモリが増える
blob 型とは(DB) MySQL は BLOB 4種、PostgreSQL は bytea、SQLite は BLOB データベースのBLOB型
画像を DB に入れてよいか 小さく・少なく・整合性が要るなら可。大きく・多いならストレージ ファイルはDBに入れるか
Azure の Blob とは Azure のオブジェクトストレージ。ブロック・追加・ページの3種 Azure Blob Storageとは

確認環境:Ubuntu 24.04.5 LTS の上で、JavaScript の Blob・File・Blob URL・FileReader・fetch・FormData・IndexedDB・Web Worker・canvas の挙動は、Chromium 153.0.8010.12(Playwright 1.63.0、ヘッドレス)で 127.0.0.1 に置いた自分のページ(Python 3.13.18 の http.server)を開いて確かめました。メモリの実測は、Chromium の全プロセスの RSS(/proc の VmRSS の合計)の差で測っています。Node.js 22.23.4 の Blob も実行しました。データベースは、SQLite 3.53.1(Python の sqlite3)、PostgreSQL 16.15(作業用ディレクトリに initdb して 127.0.0.1 の別ポートで起動)、MariaDB 10.11.14(Ubuntu のパッケージを展開して 127.0.0.1 の別ポートで起動。MySQL 互換)に同じ PNG(1,065 バイト)を入れて取り出し、cmp で元のファイルと一致することを確かめました。Blob・URL の仕様は MDN、BLOB 型の仕様は MySQL 8.4・PostgreSQL 16・SQLite の公式ドキュメント、Azure Blob Storage は Microsoft Learn で確かめています。図は mermaid 11.16.0 で描画を確かめました(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Blobとは|JavaScriptのBlob URL・DBのBLOB型の違いと使い方」

Blobとは(意味の使い分け)

この節では、「Blob」という言葉が指す4つのものと、どの文脈でどれを指しているのかが分かります。

Blob は「Binary Large OBject」の略で、画像・音声・PDF・暗号化されたデータなど、中身の構造をデータベースやプログラムが解釈しない「バイトの塊」を指します。 文字列や数値のように「中身の形式が決まっているデータ」と対比される言葉です。同じ言葉が、次の4つの場面で使われます。

文脈 指しているもの 見分け方
JavaScript(ブラウザ・Node.js) Blob オブジェクト。size と type を持つ読み取り専用のバイト列。File はその拡張 new Blob・response.blob()・files[0] が出てくる
Blob URL(オブジェクト URL) blob:http://example.com/UUID の形の仮の URL。Blob を img や a タグから参照するためのもの URL が blob: で始まる。DevTools で見かける
データベースの型 MySQL の BLOB・MEDIUMBLOB など、PostgreSQL の bytea、SQLite の BLOB、Oracle・SQL Server の BLOB/VARBINARY(MAX) CREATE TABLE の列の型に出てくる
クラウドのストレージ Azure Blob Storage(Microsoft のオブジェクトストレージ)。AWS の S3・Google Cloud Storage にあたる 「コンテナー」「ストレージアカウント」と一緒に出てくる

このほか、Git の内部ではファイルの中身を保存するオブジェクトを「blob」と呼び(git cat-file -t で blob と表示されます)、画像処理では「連結した画素の塊」を blob と呼びます。どれも「中身を解釈せずに塊として扱う」という意味で共通しています。

1

JavaScript の Blob

ブラウザの中で、ファイルのようなデータを持ち運ぶ入れ物。アップロード・ダウンロード・画像の表示に使う。

この記事の主役

2

Blob URL

Blob に付ける仮の URL。サーバーに送らずに、メモリの中のデータを img・a・iframe から参照できる。

createObjectURL

3

DB の BLOB 型

テーブルの列にバイナリをそのまま入れる型。文字コードや照合順序を持たない。

bytea・MEDIUMBLOB

4

Azure Blob Storage

ファイルを「BLOB」として URL 付きで保存するクラウドのサービス。S3 と同じ位置づけ。

公式ドキュメントの範囲

JavaScriptのBlobとは(new Blobの作り方とsize・type)

この節では、JavaScript の Blob がどういうオブジェクトで、どう作り、何が入っているのかが、実行した結果で分かります。

JavaScript の Blob は、「バイト列」と「MIME タイプ」の2つを持つ、変更できない(immutable)オブジェクトです。 MDN は「Blob インターフェイスは blob、すなわち不変の生データであるファイルのようなオブジェクトを表します」と説明しています。作り方は new Blob(部品の配列, { type: MIMEタイプ }) で、部品には文字列・ArrayBuffer・TypedArray・別の Blob を混ぜて渡せます。

const b = new Blob(["こんにちは, Blob"], { type: "text/plain" });
console.log(b.size, b.type, String(b));
console.log(await b.text());
const ab = await b.arrayBuffer();
console.log(ab.byteLength, [...new Uint8Array(ab).slice(0, 8)]);
// 部品は混ぜられる(Uint8Array・文字列・Blob)
const mixed = new Blob([new Uint8Array([0x41, 0x42]), "CD", new Blob(["EF"])]);
console.log(await mixed.text());

Chromium 153 で実行した結果です。

21 "text/plain" "[object Blob]"
"こんにちは, Blob"
21 [227, 129, 147, 227, 130, 147, 227, 129]   ← e3 81 93 … = 「こ」「ん」の UTF-8
"ABCDEF"

「こんにちは, Blob」は 11 文字ですが、size は 21 です。size は文字数ではなくバイト数で、文字列は UTF-8 に変換されて入ります(ひらがな1文字=3バイト、ASCII 1文字=1バイト)。

書いたコード 結果 読み取れること
new Blob() size 0・type "" 空の Blob が作れる
new Blob([], {type:"Image/PNG"}) type "image/png" type は小文字に直される
new Blob([], {type:"text/plain\n"}) type "" 印字できない文字が入ると空になる(エラーにはならない)
new Blob([{a:1}]) size 15 オブジェクトは文字列化され [object Object] が入る。JSON は自分で stringify する
b.slice(0, 15) 「こんにちは」・type "" slice はバイト単位。type は引き継がれず、第3引数で指定する
JSON.stringify(b) {} JSON には入らない。送るなら FormData か Base64
structuredClone(b).size 21 postMessage・IndexedDB にはそのまま渡せる
b instanceof File false Blob は File ではない(逆は true)

new Blob("abc") のように配列で囲まずに渡すと、TypeError: Failed to construct 'Blob': The provided value cannot be converted to a sequence. になります。第1引数は必ず配列です。

Blob の型(type)は「自己申告」

type は、中身を検査して決まるものではなく、作った側が付けるラベルです。PNG のバイト列を text/plain で作ってもエラーにはなりません。fetch の response.blob() では応答の Content-Type が、<input type="file"> の File では拡張子から推定した値が入ります。中身を確かめたいときは、先頭のバイト(PNG なら 89 50 4E 47)を見ます。先頭バイトの読み方は、関連記事「バイナリエディタとは|使い方・おすすめとxxdで読む実例・戻し方」で扱っています。

BlobとFile・ArrayBuffer・Base64(data URL)の違い

この節では、バイナリを扱うときに一緒に出てくる File・ArrayBuffer・TypedArray・Base64 と Blob の関係と、相互の変換方法が分かります。

File は「名前と更新日時を持つ Blob」、ArrayBuffer は「中身を直接読み書きできる生のメモリ」、Base64 は「バイナリを文字だけで表した文字列」です。 Blob は中身を直接いじれない代わりに、巨大でも JS のヒープを圧迫せず、URL を付けたりストリームで読んだりできます。

Blob / File ArrayBuffer / Uint8Array Base64(data URL)
何か 読み取り専用のバイトの塊+type 読み書きできる固定長のメモリ バイナリを A〜Z a〜z 0〜9 + / の文字で表した文字列
中身の変更 できない(slice で切り出す) できる(u8[0] = 0xff) 文字列なので作り直す
大きさ 元のバイト数 元のバイト数 1.33 倍(実測 1,048,576 → 1,398,141 文字)
img・a タグで使う URL.createObjectURL(64 文字の URL) いったん Blob にする そのまま src・href に書ける
JSON・localStorage に入る 入らない({}・[object Blob] になる) 入らない 入る
向いている場面 ファイルの受け渡し・表示・ダウンロード バイトの加工・パース・WebGL・暗号 小さな画像の埋め込み・JSON で送る

相互の変換は次のとおりです(すべて Chromium 153 で実行)。

// Blob → ArrayBuffer / Uint8Array
const ab  = await blob.arrayBuffer();
const u8  = await blob.bytes();            // Uint8Array を直接返す(新しめの API)
// ArrayBuffer → Blob
const blob2 = new Blob([u8], { type: "application/octet-stream" });
// Blob → Base64(data URL)
const dataUrl = await new Promise(ok => {
  const fr = new FileReader();
  fr.onload = () => ok(fr.result);         // "data:text/plain;base64,SGk="
  fr.readAsDataURL(blob);
});
// Base64(data URL)→ Blob:fetch に食わせるのが短い
const blob3 = await (await fetch(dataUrl)).blob();
// Blob → File(名前を付ける)
const file = new File([blob], "memo.txt", { type: blob.type, lastModified: Date.now() });

File のコンストラクターは第2引数のファイル名が必須で、省くと TypeError: Failed to construct 'File': 2 arguments required, but only 1 present. になります。<input type="file"> で選んだファイルは、次のような File として届きました。

{ name: "upload_sample.csv", size: 17, type: "text/csv",
  lastModified: 1793358752883, isFile: true, isBlob: true,
  text: "id,name\n1,田中\n", webkitRelativePath: "" }

type は拡張子 .csv から text/csv と推定され、lastModified はファイルの更新日時のミリ秒です。Base64 の仕組みと各言語での変換は、関連記事「Base64エンコード各言語コード一覧|sha256ハッシュのコマンド早見表」で扱っています。

画像を画面に出すとき

やりがちreadAsDataURL で Base64 にして img.src に入れる。10MB の画像なら 13.3MB の文字列が JS のヒープに乗り、DOM にも残る
→
代わりにURL.createObjectURL(blob) を img.src に入れる。URL は 64 文字で、1MB・10MB どちらも 1ms 前後で作れた。表示し終えたら revokeObjectURL

Base64 が向くのは、数 KB のアイコンを CSS や JSON に埋め込むときです

Blobの中身を読む(text・arrayBuffer・stream・FileReader)

この節では、Blob から文字列やバイト列を取り出す方法と、以前からある FileReader との使い分け、文字コードのつまずきが分かります。

今は await blob.text()・await blob.arrayBuffer()・await blob.bytes() の Promise 版が短く書けます。 FileReader はイベント(onload)で結果を受け取る以前からの API で、Base64 にしたいとき(readAsDataURL)と、文字コードを指定して読みたいとき(readAsText(blob, "Shift_JIS"))に今も使います。

やりたいこと Promise 版(新しい書き方) FileReader 版
文字列として読む(UTF-8) await blob.text() fr.readAsText(blob)
Shift_JIS など別の文字コードで読む new TextDecoder("shift_jis").decode(await blob.arrayBuffer()) fr.readAsText(blob, "Shift_JIS")
バイト列として読む await blob.arrayBuffer()・await blob.bytes() fr.readAsArrayBuffer(blob)
Base64(data URL)にする (Uint8Array.prototype.toBase64 は Chromium 153 で使えた) fr.readAsDataURL(blob)
大きなものを少しずつ読む blob.stream().getReader() blob.slice() を順に読む

Shift_JIS の「こんにちは」(10 バイト)を入れた Blob を、4通りで読んだ結果です。

blob.text()                         → "����ɂ���"   (UTF-8 として読んで化けた)
fr.readAsText(blob)                 → "����ɂ���"   (既定は UTF-8)
fr.readAsText(blob, "Shift_JIS")    → "こんにちは"
new TextDecoder("shift_jis").decode(await blob.arrayBuffer()) → "こんにちは"

Windows で作った CSV を blob.text() で読んで化けるのは、この既定が UTF-8 だからです。 type に charset=shift_jis を付けても text() は UTF-8 で読みます(type は読み方に影響しません)。

readAsDataURL の結果は type によって変わりました。type: "text/plain" なら data:text/plain;base64,SGk=、type を付けないと data:application/octet-stream;base64,SGk= です。Blob の type が空だと、data URL の MIME タイプも「中身不明」になります。

Blob URL(createObjectURL)で画像を表示・ダウンロードする

この節では、Blob に仮の URL を付けて img で表示し、a タグでダウンロードさせる手順と、そのとき裏で何が起きているかが分かります。

Blob URL(オブジェクト URL)は、URL.createObjectURL(blob) が返す blob:http://127.0.0.1:46110/fc19362a-c5d3-4d49-90fa-187cfea396d9 のような文字列です。 「blob:」の後ろに作ったページのオリジン、その後ろに UUID が付き、長さは 64 文字でした。この URL を img・a・iframe・fetch に渡すと、ブラウザがメモリの中の Blob を読みに行きます。サーバーには何も送りません。

1

Blob を用意する

fetch の response.blob()、input[type=file] の File、canvas.toBlob、new Blob のどれでもよい。手元では fetch("/photo.png") の応答(image/png・1,065 バイト)を使った。

size 1065・type image/png

2

URL を作る

const url = URL.createObjectURL(blob)。呼ぶたびに別の URL ができる(同じ Blob でも)。

blob:http://127.0.0.1:46110/fc19…

3

img.src か a.href に入れる

img なら img.src = url で表示される(naturalWidth 400・naturalHeight 300 で読めた)。ダウンロードなら a.href = url; a.download = "hello.txt"; a.click()。

download 属性で保存名を決める

4

使い終わったら解放する

URL.revokeObjectURL(url)。img の onload の中、ダウンロードなら click() の直後で呼ぶ。

解放後の URL は使えない

// 画像の表示
const res  = await fetch("/photo.png");
const blob = await res.blob();                 // { size: 1065, type: "image/png" }
const url  = URL.createObjectURL(blob);        // blob:http://127.0.0.1:46110/fc19362a-…
img.onload = () => URL.revokeObjectURL(url);   // 表示が終わったら解放
img.src = url;

// ダウンロード
function download(blob, filename) {
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = filename;
  a.click();
  URL.revokeObjectURL(a.href);
}
download(new Blob(["hello, blob\n"], { type: "text/plain" }), "hello.txt");

Chromium で実行した結果です。ダウンロードは Playwright の download イベントで受け取り、保存したファイルの中身まで確かめました。

createObjectURL → blob:http://127.0.0.1:46110/fc19362a-c5d3-4d49-90fa-187cfea396d9 (64 文字)
img.onload      → naturalWidth 400, naturalHeight 300, complete true
fetch(url)      → status 200, content-type image/png, 1065 bytes
download event  → suggestedFilename "hello.txt", url blob:http://127.0.0.1:46110/4ddcc0cc-…
saved file      → "hello, blob\n"

fetch(url) で Blob URL を読むと、ステータス 200 と Blob の type が Content-Type として返りました。Blob URL は「ブラウザの中だけで通用する、ミニ HTTP サーバーの URL」と考えると挙動が読めます。

canvas の画像を Blob にする

canvas の描画結果は canvas.toBlob(callback, type, quality) で Blob になります。200×100 の青い矩形を3つの形式で出した結果です。

toBlob()                     → 884 bytes, image/png
toBlob(cb, "image/jpeg", 0.8) → 897 bytes, image/jpeg
toBlob(cb, "image/webp", 0.8) → 610 bytes, image/webp
toDataURL()                  → 1,202 文字(PNG の Base64。Blob の 1.36 倍)

Blob URLの寿命(ページを閉じると無効・別オリジンから読めない)

この節では、Blob URL がいつまで使えて、どこから使えるのかが、実際に試した結果で分かります。

Blob URL は「作ったページ(document)が生きている間だけ」有効です。 MDN は「URL の寿命は、それを作成したウィンドウ内の document と結び付けられています」と書いています。ページを閉じる・再読み込みする・revokeObjectURL を呼ぶ、のどれかで無効になります。Chromium 153 で試した結果を表にしました。

試したこと 結果 原文・表示
作ったページから fetch(url) 読める 200・image/png・1,065 バイト
revokeObjectURL の後に fetch(url) 読めない TypeError: Failed to fetch・コンソールに net::ERR_FILE_NOT_FOUND
revoke の後、表示済みの img 表示は残る naturalWidth 400 のまま。読み込みが終わっていれば消えない
revoke の後、別の img に同じ URL 読めない onerror が呼ばれた
同じブラウザの別タブで URL を開く(作ったページは開いたまま) 開ける 200・「from blob」が表示
作ったページを閉じてから別タブで開く 開けない net::ERR_FILE_NOT_FOUND。画面は「Your file couldn't be accessed」
ページを再読み込みしてから元の URL を fetch 読めない TypeError: Failed to fetch
別オリジン(localhost:46110)のページから fetch(url) 読めない TypeError: Failed to fetch
別オリジンのページから location.href = url 移動しない コンソールに Not allowed to load local resource: blob:http://127.0.0.1:46110/fa89…
同じオリジンのページから location.href = url 移動する 200・Blob の HTML が表示
iframe の src に Blob URL(text/html) 表示される 中の location.origin は親と同じ http://127.0.0.1:46110

1保存して後で使えない

Blob URL を localStorage や DB に保存しても、次に開いたときには ERR_FILE_NOT_FOUND になる。保存するなら Blob そのもの(IndexedDB)か、サーバーの URL。

2オリジンが付いている

URL に作ったページのオリジンが含まれ、別オリジンからは読めない。127.0.0.1 と localhost も別オリジン扱いだった。

3revoke しても表示済みは消えない

img の読み込みが終わってから revoke しても画像は残った。onload の中で revoke するのが安全で、画像を差し替えるときに前の URL を解放する。

iframe に Blob URL を入れたときのオリジンは、Blob を作ったページのオリジンを引き継ぎました(MDN の説明どおりです)。text/html の Blob を iframe に入れると、中のスクリプトは親と同じオリジンで動きます。他人が作った HTML をそのまま Blob にして表示する使い方は避け、必要なら sandbox 属性を付けます。

revokeObjectURLしないとメモリが増える(実測)

この節では、Blob URL を解放し忘れたときに、どれだけメモリが増え、何をすれば戻るのかが、実測した数字で分かります。

4MB の Blob を 100 個作って createObjectURL し、JS の変数を捨てて GC しても、Chromium 全体のメモリは 455MB 増えたままでした。 revokeObjectURL を全部呼ぶと 56MB まで戻りました。URL が付いた Blob は、JS から参照されなくなっても GC の対象にならないためです(URL の文字列からいつでも読める必要があるので、ブラウザが保持し続けます)。

+455MB4MB×100 を createObjectURL変数を捨てて gc() しても減らない
+56MBrevokeObjectURL を 100 回2秒後に測定。ほぼ元の値
+55MBURL を付けずに Blob を 100 個作って捨てたURL が無ければ GC で消える

revoke せずにページを再読み込みすると、2〜20 秒後の測定で +117〜114MB まで下がりました。MDN の「ブラウザーは、文書がアンロードされた際にこれらのオブジェクト URL をメモリーから解放します」という記述のとおり、document が消えれば解放されます。ただし revoke のようにすぐ元の値まで戻るわけではなく、解放のタイミングはブラウザ任せになります。

測り方は、Chromium の全プロセス(ブラウザ・レンダラー・GPU など9プロセス)の VmRSS を /proc から合計し、起動直後との差を取りました。増えたのは主にブラウザプロセス(182MB → 599MB)で、Blob の実体はレンダラーではなくブラウザプロセス側に置かれていることも分かります。

単一ページアプリ(SPA)では、ページの再読み込みが起きないので、画像のプレビューを差し替えるたびに URL を作って捨てていると、使った分だけ増え続けます。 前の URL を revoke してから次を作る、という一行で防げます。

let currentUrl = null;
function showPreview(file) {
  if (currentUrl) URL.revokeObjectURL(currentUrl);   // 前のを解放
  currentUrl = URL.createObjectURL(file);
  preview.src = currentUrl;
}

BlobとBase64(data URL)の大きさ・速さの実測

この節では、同じデータを Blob URL と Base64(data URL)で扱ったときの大きさと、変換にかかる時間が分かります。

Base64 は 3 バイトを 4 文字で表すので、大きさは必ず 1.33 倍になります。 1MB と 10MB のバイナリで、Blob URL を作る時間・Base64 にする時間・Base64 から Blob に戻す時間を測りました(Chromium 153、各1回)。

測ったこと 1MB(1,048,576 バイト) 10MB(10,485,760 バイト)
Blob URL の長さ 64 文字 64 文字
data URL の長さ 1,398,141 文字(1.333 倍) 13,981,053 文字(1.333 倍)
URL.createObjectURL 0.40ms 8.0ms
FileReader.readAsDataURL 7.9ms 38.5ms
Uint8Array.toBase64() 1.3ms 7.7ms
data URL → fetch().blob() で戻す 32.0ms 274.8ms
blob.arrayBuffer() 1.9ms 17.5ms
blob.text() 3.1ms 122.5ms
  • Blob URL を作る時間は、データの大きさにほとんど比例しません。 10MB でも 8ms で、コピーではなく「参照に名前を付けている」だけだと分かります。
  • Base64 は作るより戻すほうが遅く、10MB で 275ms かかりました。画面に出す目的で Base64 を経由する理由はありません。
  • blob.text() は UTF-8 のデコードが入るため、バイナリを文字列として読むと遅く、しかも壊れます。バイナリは arrayBuffer() か bytes() で読みます。
  1. 1画面に出す・ダウンロードさせる → Blob URLcreateObjectURL。使い終わったら revoke
  2. 2サーバーに送る → FormData に Blob/File をそのままmultipart/form-data。Base64 にしない
  3. 3バイトを加工する → arrayBuffer / bytesUint8Array にしてから new Blob で戻す
  4. 4ブラウザに保存する → IndexedDB に Blob のままFile を入れて取り出すと File のまま戻った
  5. 5JSON や CSS に埋め込む → Base64(data URL)数 KB まで。1.33 倍になる

fetchのresponse.blob()・FormData・Worker・Node.jsのBlob

この節では、Blob がブラウザの他の API とどうつながるか、Node.js ではどう使えるかが、実行した結果で分かります。

fetch の応答は response.blob() で Blob になり、type には応答の Content-Type が入ります。 本文は一度しか読めないので、blob() を2回呼ぶと TypeError: Failed to execute 'blob' on 'Response': body stream already read になります。404 でも本文(エラーページの HTML)が Blob になるので、response.ok を先に見ます。

fetch("/nothing") → ok false, status 404, blob: size 335, type text/html   ← エラーページが Blob になる
fetch("/dot.png") → blob() 2回目: TypeError: Failed to execute 'blob' on 'Response': body stream already read

FormData に Blob を append すると、multipart/form-data の1パートになります。第3引数でファイル名を付けないと、ファイル名は blob、type の無い Blob は application/octet-stream で送られました。

Content-Disposition: form-data; name="f"; filename="x.csv"
Content-Type: text/csv
csv,data
Content-Disposition: form-data; name="g"; filename="blob"
Content-Type: application/octet-stream
noname

大きなファイルを分割して送るときは blob.slice(start, end) です。10MB+5 バイトを 4MB ずつ切ると、4,194,304・4,194,304・2,097,157 バイトの3つになりました。fetch と FormData の送り方は、関連記事「JavaScript fetchの使い方|用途別コピペ関数と実行結果」と「FormDataの使い方|fetchで送信・ファイルアップロードをコピペ解説」で扱っています。

つなぎ先 やったこと 結果
Web Worker postMessage(blob) で渡す Worker 側で instanceof Blob が true、text() で読めた。Worker のコード自体も Blob URL で作れた
IndexedDB File を put して get コンストラクターは File、name は idb.txt、text は abc。Blob のまま保存できる
localStorage setItem("b", blob) "[object Blob]" という文字列になる。入らない
JSON.stringify Blob を渡す {}。中身は消える
Node.js 22 new Blob(["hello"," ","node"]) size 10・text "hello node"。URL.createObjectURL も使え、fetch(blobUrl) で 200 が返った。fs.openAsBlob(path) でファイルを Blob にできる

Node.js の Blob はグローバルにあり(node:buffer の Blob と同じもの)、ブラウザと同じ text()・arrayBuffer()・slice() が使えます。ブラウザ向けのコードを Node.js でテストするときに、ファイルを Blob として渡すのに fs.openAsBlob が便利でした(type は空で返るので、必要なら new Blob([b], {type}) で付け直します)。

データベースのBLOB型(SQLite・PostgreSQL bytea・MySQL)に画像を入れる

この節では、データベースの BLOB 型がどういう型で、各 DB で何という名前なのか、同じ PNG を入れて取り出すとどうなるかが分かります。

データベースの BLOB 型は、文字コードも照合順序も持たない「バイトの列」をそのまま保存する列の型です。 MySQL の公式ドキュメントは、BLOB は「binary strings (byte strings)」として扱われ、比較と並べ替えはバイトの数値で行われる、TEXT は文字セットと照合順序で比較される、と区別しています。DB ごとの名前と上限を表にしました。

DB 型の名前 1つの値の上限(公式) 手元で確かめた
MySQL/MariaDB TINYBLOB・BLOB・MEDIUMBLOB・LONGBLOB(TEXT 4種と対応) 255B・64KB・16MB・4GB。送れる大きさは別途 max_allowed_packet MariaDB 10.11.14
PostgreSQL bytea(別に「ラージオブジェクト」もある) 1フィールド 1GB(Limits の表) PostgreSQL 16.15
SQLite BLOB(型の宣言はゆるく、入れた値ごとに型が決まる) 既定 10 億バイト(SQLITE_MAX_LENGTH)、実装上の上限 2,147,483,645 SQLite 3.53.1
Oracle・SQL Server SQL Server は varbinary(max)(Oracle は BLOB) varbinary(max) は 2^31-1 バイト(約 2GB、Microsoft Learn) 公式の範囲

SQLite:Python の bytes をそのまま入れる

import sqlite3
data = open("photo.png", "rb").read()              # 1065 バイト
con = sqlite3.connect("t110db.sqlite")
con.execute("CREATE TABLE images (id INTEGER PRIMARY KEY, name TEXT, mime TEXT, data BLOB)")
con.execute("INSERT INTO images (name, mime, data) VALUES (?, ?, ?)", ("photo.png", "image/png", data))
con.commit()
row = con.execute("SELECT id, name, mime, typeof(data), length(data), substr(hex(data),1,16) FROM images").fetchone()
print(row)
blob = con.execute("SELECT data FROM images WHERE id=1").fetchone()[0]
print(type(blob).__name__, blob == data)
open("out_sqlite.png", "wb").write(blob)
(1, 'photo.png', 'image/png', 'blob', 1065, '89504E470D0A1A0A')
bytes True
$ cmp photo.png out_sqlite.png && echo identical
identical

SQLite は列の型宣言に関わらず入れた値の型で保存するので、同じ列に文字列 'abc' を入れると typeof(data) は text になりました。SQL で直接バイナリを書くときは X'89504E47' の16進リテラルで、これは blob になります。Python 側は bytes を渡せば BLOB、str を渡せば TEXT です。大きな BLOB を少しずつ読むには con.blobopen("images", "data", 1) があり、全体をメモリに載せずに先頭 8 バイトだけ読めました(89504e470d0a1a0a)。

PostgreSQL:bytea と \x の16進表記

CREATE TABLE images (id serial PRIMARY KEY, name text, mime text, data bytea);
-- psql で、ファイルを Base64 にして decode() で入れる
\set content `base64 -w0 photo.png`
INSERT INTO images (name, mime, data) VALUES ('photo.png', 'image/png', decode(:'content', 'base64'));
INSERT INTO images (name, mime, data) VALUES ('hex', 'application/octet-stream', '\x89504e47');
SELECT id, name, pg_typeof(data), length(data), substring(data from 1 for 8) AS head FROM images;
 id |   name    | pg_typeof | length |        head
----+-----------+-----------+--------+--------------------
  1 | photo.png | bytea     |   1065 | \x89504e470d0a1a0a
  2 | hex       | bytea     |      4 | \x89504e47

postgres=# SHOW bytea_output;   → hex
postgres=# SELECT pg_column_size(data) FROM images WHERE id=1;   → 1069(長さ4バイト+本体)
$ psql -At -c "SELECT encode(data,'base64') FROM images WHERE id=1" | base64 -d > out_pg.png
$ cmp photo.png out_pg.png && echo identical
identical

PostgreSQL の bytea は、入出力が \x で始まる16進の文字列です(公式ドキュメント:hex 形式が既定で、以前の escape 形式より速く、新しいアプリケーションでは hex を使う)。形式が合わない文字列を入れると ERROR: invalid input syntax for type bytea になりました。アプリケーションからは、ドライバーが bytes(Python)や byte[](Java)をそのまま bytea にしてくれるので、16進の文字列を自分で組み立てなくて済みます。

bytea とは別に「ラージオブジェクト」(lo_from_bytea などで扱い、OID で参照する)もあります。bytea は行の中に入り 1GB まで、ラージオブジェクトは別テーブルに分割して置かれ、途中から読み書きできる、という違いです。

MariaDB(MySQL 互換):LOAD_FILE と max_allowed_packet

CREATE TABLE images (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), mime VARCHAR(50), data MEDIUMBLOB);
INSERT INTO images (name, mime, data) VALUES ('photo.png', 'image/png', LOAD_FILE('/path/photo.png'));
INSERT INTO images (name, mime, data) VALUES ('hex', 'application/octet-stream', X'89504E47');
SELECT id, name, mime, LENGTH(data) AS bytes, HEX(LEFT(data, 8)) AS head FROM images;
SELECT data INTO DUMPFILE '/path/out_mdb.png' FROM images WHERE id = 1;
id  name       mime                      bytes  head
1   photo.png  image/png                 1065   89504E470D0A1A0A
2   hex        application/octet-stream  4      89504E47

$ cmp photo.png out_mdb.png && echo identical
identical

-- BLOB と TEXT の比較の違い(BLOB はバイトで比較するので大文字小文字を区別する)
CREATE TABLE cmp (b BLOB, t TEXT); INSERT INTO cmp VALUES ('abc', 'abc');
SELECT b = 'ABC' AS blob_eq, t = 'ABC' AS text_eq FROM cmp;   → blob_eq 0, text_eq 1

MySQL 系で BLOB を扱うときに最初に当たる壁が max_allowed_packet(既定 16MB)です。18MB の INSERT 文を送ると、クライアントには ERROR 2006 (HY000): Server has gone away、サーバーのエラーログには Aborted connection … (Got a packet bigger than 'max_allowed_packet' bytes) と出ました。サーバー側で SET GLOBAL max_allowed_packet = 67108864、クライアント側でも --max-allowed-packet=64M を指定すると、9MB の値が入りました(公式ドキュメントも「サーバーとクライアントの両方で変える」としています)。TINYBLOB(255 バイト)に 300 バイト入れると、strict モードでは ERROR 1406 (22001): Data too long for column 'd' at row 1 です。

BLOB 型が向くもの

数十 KB までの小さなもの(サムネイル・アイコン・署名画像)

行と一緒にトランザクションで消えてほしいもの

暗号化済みのデータ・鍵・証明書

件数が少なく、バックアップを DB 1つで済ませたいもの

ストレージ(S3・Azure Blob)が向くもの

数 MB 以上の画像・動画・PDF

件数が増え続けるもの(ユーザーの投稿)

CDN から直接配信したいもの

DB のバックアップ・レプリケーションを軽くしたいとき

ファイルはDBに入れるか(判断表と実測)

この節では、「画像を DB の BLOB 列に入れるか、ファイル/ストレージに置いてパスだけ DB に入れるか」を決める基準と、その根拠になる実測が分かります。

小さく・少なく・行と一緒に消えてほしいなら BLOB 列、大きく・増え続け・直接配信したいならストレージにパス(URL)だけ、が基本です。 50KB のデータ 2,000 件(約 100MB)を SQLite の BLOB 列と個別ファイルの両方に入れて測りました(tmpfs 上、Python 3.13、各1回)。

測ったこと 個別ファイル SQLite の BLOB 列
2,000 件の書き込み 111ms 493ms(1トランザクション・WAL)
ランダムに 5,000 回読む 253ms 207ms
占める大きさ 102.4MB 106.5MB
count(*)(BLOB 列を触らない) ― 2.7ms
sum(length(data))(BLOB 列を全部なめる) ― 6.3ms
SQL のダンプ(バックアップ)の大きさ ― 204.9MB(16進の文字列になるので 2 倍)
  • 小さなファイルを「読む」速さは、BLOB 列のほうがわずかに速いか同じでした。SQLite の公式ページ「35% Faster Than The Filesystem」も、10KB 前後の小さな BLOB なら個別ファイルの fread/fwrite より約 35% 速く、領域も約 20% 少なくて済む一方、大きくなるとファイルシステムが有利になる、と説明しています。
  • 一方で、SQL のダンプは2倍の大きさになり、BLOB 列を含む行を SELECT するたびに転送量が増えます。 一覧画面で SELECT * を書くと、不要な画像まで毎回読むことになります。
  • ストレージに置く場合は、DB には「パス(キー)・MIME タイプ・大きさ・ハッシュ」だけを入れ、ファイルの削除と行の削除がずれないように設計します。
  • 11件の大きさは 100KB 未満か超えるならストレージ。MySQL なら max_allowed_packet にも当たる
  • 2件数は増え続けないかユーザー投稿のように増えるものは、DB のバックアップ時間が伸び続ける
  • 3行と一緒にトランザクションで消したいかはい、なら BLOB 列の利点が大きい。ストレージだと削除漏れの対策が要る
  • 4ブラウザや CDN から直接配信したいかはい、ならストレージ。DB の BLOB はアプリを経由しないと配信できない
  • 5一覧の SELECT で BLOB 列を除いているかBLOB 列を持つテーブルで SELECT * を書かない。列名を書く

アップロードされたファイルの保存先の設計と命名は、関連記事「ファイルアップロードの保存先設計|DBかストレージかの判断表と命名規則」で扱っています。

Azure Blob Storageとは(公式ドキュメントの範囲)

この節では、クラウドの文脈で出てくる「Blob」、Microsoft Azure の Blob Storage が何で、どういう構造と種類を持つかが分かります。

Azure Blob Storage は、Microsoft Azure のオブジェクトストレージで、AWS の S3・Google Cloud Storage にあたるサービスです。 ここでの「BLOB」は「コンテナーの中に置く1つのファイル(オブジェクト)」のことで、URL(https://アカウント名.blob.core.windows.net/コンテナー名/BLOB名)で参照します。この記事の確認では Azure に接続していないため、Microsoft Learn の記述の範囲で整理します。

項目 内容(Microsoft Learn、2026年10月29日時点)
向いている用途 画像やドキュメントをブラウザーに直接配信、分散アクセス用のファイル、動画・音声のストリーミング、ログの書き込み、バックアップ・アーカイブ、分析用データの格納
構造 ストレージアカウント → コンテナー(ディレクトリのように BLOB を整理)→ BLOB(データ本体)
ブロック BLOB テキストとバイナリを格納。個別に管理できるブロックで構成。最大約 190.7TiB。ふつうのファイルはこれ
追加 BLOB 追加操作向けに最適化。仮想マシンからのログ記録などに
ページ BLOB 最大 8TiB のランダムアクセスファイル。VHD を置いて仮想マシンのディスクにする
アクセス層 ホット(頻繁に使う)・クール(30 日以上保持)・コールド(90 日以上)・アーカイブ(180 日以上、オフラインで読む前にリハイドレートが必要、最大 15 時間)

JavaScript の Blob と直接の関係はありませんが、ブラウザで File を Azure の SDK に渡してアップロードする、という形で両方が同時に出てくることはあります。Azure の画面と料金の全体像は、関連記事「Azure Portalとは|Azureの使い方・画面・料金を初心者向けに解説」で扱っています。

Blobのよくあるエラー・つまずき(原文と直し方)

この節では、Blob まわりで出るエラーの原文と、原因・直し方が分かります。すべて手元で再現した文言です。

エラーの原文(Chromium 153・各 DB) 原因 直し方
TypeError: Failed to construct 'Blob': The provided value cannot be converted to a sequence. new Blob("abc") のように配列で囲んでいない new Blob(["abc"])
TypeError: Failed to execute 'createObjectURL' on 'URL': Overload resolution failed. Blob/File 以外(文字列・ArrayBuffer・undefined)を渡した ArrayBuffer は new Blob([buf]) にしてから渡す。await 忘れで undefined になっていないか見る
TypeError: Failed to construct 'File': 2 arguments required, but only 1 present. File のファイル名を省いた new File([blob], "name.ext", {type})
TypeError: Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'. FileReader に文字列や files(FileList)を渡した files[0] のように1つの File を渡す
net::ERR_FILE_NOT_FOUND(blob: の URL)・TypeError: Failed to fetch revoke 済み・作ったページを閉じた・再読み込みした・別オリジン URL を保存して使い回さない。必要な間は revoke しない
Not allowed to load local resource: blob:http://… 別オリジンのページから Blob URL へ移動しようとした 同じオリジンで作るか、サーバーの URL を使う
TypeError: Failed to execute 'blob' on 'Response': body stream already read response.blob() と text() など本文を2回読んだ 1回だけ読む。2回要るなら response.clone()
InvalidCharacterError: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range. 日本語などを btoa に直接渡した TextEncoder でバイト列にしてから Base64 にする。Blob なら readAsDataURL
文字化け(����ɂ���) Shift_JIS のファイルを text() で読んだ(既定は UTF-8) readAsText(blob, "Shift_JIS") か TextDecoder("shift_jis")
ERROR 2006 (HY000): Server has gone away(MySQL/MariaDB) INSERT が max_allowed_packet(既定 16MB)を超えた。エラーログに Got a packet bigger than 'max_allowed_packet' bytes サーバーとクライアント両方の max_allowed_packet を上げるか、ストレージに置く
ERROR 1406 (22001): Data too long for column 'd' at row 1 TINYBLOB(255B)などの上限を超えた MEDIUMBLOB/LONGBLOB にする
ERROR: invalid input syntax for type bytea(PostgreSQL) bytea の形式(\x… か escape)に合わない文字列を入れた ドライバーに bytes を渡す。SQL で書くなら '\x89504e47' か decode(…, 'base64')

よくある質問

Q. Blob とは何の略ですか? A. Binary Large OBject の略です。もともと「かたまり」を意味する英単語で、IT では「中身の形式を解釈しないバイトの塊」を指します。JavaScript の Blob、データベースの BLOB 型、Azure Blob Storage は、どれもこの意味です。

Q. JavaScript の Blob と File の違いは何ですか? A. File は Blob を継承したもので、name(ファイル名)と lastModified(更新日時)が加わっています。input[type=file] で選んだものは File、fetch の response.blob() や new Blob で作ったものは Blob です。File は Blob として扱える(instanceof Blob が true)ので、Blob を受け取る API には File も渡せます。

Q. blob: で始まる URL は何ですか? A. URL.createObjectURL(blob) が返す、ブラウザの中だけで通用する仮の URL です。作ったページが開いている間だけ有効で、ページを閉じる・再読み込みする・revokeObjectURL を呼ぶと使えなくなります。別のオリジンのページからは読めません。

Q. Blob URL をコピーして別の場所で開けますか? A. 開けません。手元では、作ったページを閉じてから別タブで開くと net::ERR_FILE_NOT_FOUND になりました。後で使うなら、Blob そのものを IndexedDB に保存するか、サーバーにアップロードして普通の URL をもらいます。

Q. revokeObjectURL は本当に必要ですか? A. 必要です。URL を付けた Blob は、JS の変数を捨てても解放されません。4MB×100 個で 455MB 増え、revoke すると 56MB まで戻りました。ページの再読み込みでも解放されますが、SPA では再読み込みが起きないので、差し替えるたびに前の URL を revoke します。

Q. Blob を Base64 に変換するには? A. FileReader.readAsDataURL(blob) で data:image/png;base64,… の形になります。Base64 の部分だけ要るならカンマの後ろを取り出します。戻すときは fetch(dataUrl).then(r => r.blob()) が短いです。大きさは 1.33 倍になり、10MB で戻すのに 275ms かかったので、画面に出すだけなら Blob URL を使います。

Q. Blob の中身を文字列として読むには? A. await blob.text() です。UTF-8 として読むので、Shift_JIS のファイルは new FileReader().readAsText(blob, "Shift_JIS") か new TextDecoder("shift_jis").decode(await blob.arrayBuffer()) を使います。

Q. Blob を JSON で送れますか? A. そのままでは送れません。JSON.stringify(blob) は {} になります。ファイルを送るなら FormData に append して multipart/form-data で送るのが基本で、どうしても JSON に入れるなら Base64 にします。

Q. データベースの BLOB 型と TEXT 型の違いは? A. BLOB は文字コードを持たないバイトの列で、比較・並べ替えはバイトの値で行われます('abc' = 'ABC' が偽)。TEXT は文字セットと照合順序を持つ文字列です(既定の照合順序では真)。画像・PDF・暗号化データは BLOB、人が読む文章は TEXT です。

Q. 画像を DB の BLOB 列に入れてよいですか? A. 数十 KB までの小さなもので、件数が増え続けず、行と一緒に消えてほしいなら入れてよいです。数 MB 以上・増え続ける・CDN から直接配信したい、のどれかに当たるならストレージに置き、DB にはパスとメタデータだけ入れます。

Q. PostgreSQL に BLOB 型はありますか? A. 「BLOB」という名前の型はなく、bytea を使います。1フィールド 1GB までで、入出力は \x89504e47 のような16進の文字列です。別の仕組みとして OID で参照する「ラージオブジェクト」もあります。

Q. Azure Blob Storage の Blob は JavaScript の Blob と同じですか? A. 言葉の由来は同じ(バイナリの塊)ですが、別のものです。Azure の BLOB はクラウド上に置かれる1つのファイル(オブジェクト)で、ブロック・追加・ページの3種類があります。JavaScript の Blob はブラウザのメモリの中のデータです。ブラウザの File を Azure にアップロードする、という形で両方が同時に登場します。

まとめ

  • Blob は「形式を決めつけないバイトの塊」。JavaScript の Blob・Blob URL・DB の BLOB 型・Azure Blob Storage のどれも同じ考え方で、文脈で指すものが変わる。
  • JavaScript の Blob は new Blob([部品], {type}) で作る読み取り専用のバイト列。size はバイト数(文字列は UTF-8)、type は自己申告。File は name と lastModified を足した Blob。
  • Blob URL は URL.createObjectURL で作る 64 文字の仮の URL。作ったページが生きている間・同じオリジンからだけ使える。保存して使い回せない。
  • 解放し忘れると消えない。4MB×100 個で 455MB 増え、revokeObjectURL で 56MB に戻った。SPA では前の URL を revoke してから次を作る。
  • Base64 は 1.33 倍で、戻すのに 10MB で 275ms。画面に出す・ダウンロードさせる・サーバーに送るのは Blob のままで、Base64 は数 KB の埋め込みに限る。
  • DB の BLOB 型は MySQL が BLOB 4種(max_allowed_packet に注意)、PostgreSQL が bytea(1GB・\x 16進)、SQLite が BLOB。小さく・少なく・行と一緒に消すなら BLOB 列、大きく・増え続け・直接配信ならストレージ。

参考・出典

確認日はいずれも 2026年10月29日です。

  • MDN「Blob」:https://developer.mozilla.org/ja/docs/Web/API/Blob
  • MDN「File」:https://developer.mozilla.org/ja/docs/Web/API/File
  • MDN「URL.createObjectURL()」:https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL_static
  • MDN「URL.revokeObjectURL()」:https://developer.mozilla.org/ja/docs/Web/API/URL/revokeObjectURL_static
  • MDN「FileReader」:https://developer.mozilla.org/ja/docs/Web/API/FileReader
  • MDN「Response: blob() メソッド」:https://developer.mozilla.org/ja/docs/Web/API/Response/blob
  • W3C「File API」(Blob・Blob URL の仕様):https://w3c.github.io/FileAPI/
  • Node.js「Buffer」の Blob:https://nodejs.org/docs/latest-v22.x/api/buffer.html#class-blob
  • MySQL 8.4 Reference Manual「13.3.4 The BLOB and TEXT Types」:https://dev.mysql.com/doc/refman/8.4/en/blob.html
  • PostgreSQL 16「8.4. Binary Data Types」:https://www.postgresql.org/docs/16/datatype-binary.html
  • PostgreSQL 16「Appendix K. PostgreSQL Limits」:https://www.postgresql.org/docs/16/limits.html
  • SQLite「Implementation Limits For SQLite」:https://www.sqlite.org/limits.html
  • SQLite「35% Faster Than The Filesystem」:https://www.sqlite.org/fasterthanfs.html
  • Microsoft Learn「binary および varbinary (Transact-SQL)」:https://learn.microsoft.com/ja-jp/sql/t-sql/data-types/binary-and-varbinary-transact-sql
  • Microsoft Learn「Azure Blob Storage の概要」:https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blobs-introduction
  • Microsoft Learn「BLOB データのアクセス層」:https://learn.microsoft.com/ja-jp/azure/storage/blobs/access-tiers-overview

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Blobとは|JavaScriptのBlob URL・DBのBLOB型の違いと使い方」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

成長のヒミツ、 ぜんぶ丸わかり