SheetJSは、xlsx・xls・CSVなどの表計算ファイルをJavaScriptで読み書きするライブラリで、npmでは「xlsx」というパッケージ名で知られています。ブラウザでもNode.jsでも動き、アップロードされたExcelをJSONに変換する取込処理や、画面の一覧をxlsxでダウンロードさせる機能の実装が主な用途です。この記事では、2026年11月1日時点の最新版0.20.3を前提に、npmのxlsxが古いまま止まっている理由と入れ方、sheet_to_jsonでの取込、日付のずれ、ブラウザでの書き出し、無償版で付けられない書式、大量データの扱い、採用を見送る場面までを実装者向けに整理します。
まとめ:SheetJSは取込と形式変換向け、npm版でなくCDNの0.20.3を固定して使う
多くの形式のファイルから値を取り出す用途なら、SheetJSは有力な選択肢です。xlsxだけでなく旧形式のxlsやCSVも同じAPIで読め、結果を行ごとのオブジェクトの配列で受け取れます。
最初に確認したいのは入手元です。npm install xlsxで入るのは2022年3月の0.18.5で、GitHub Advisory Databaseに登録された深刻度Highの脆弱性2件が未修正のまま残ります。公式が案内する入手元は自社CDNで、最新の0.20.3をtgzのURLで指定して入れます。
無償のCommunity Editionで付けられるのは、表示形式・列幅・セル結合までです。フォントや罫線、塗りつぶしを作り込んだ帳票を出したいなら、有償のProを買うか、出力だけExcelJSに分ける判断になります。
SheetJSとは:表計算ファイルの読み書きとApache 2.0・有償版Pro
xlsx・xls・CSVを読み書きするライブラリであるSheetJSのCommunity Editionは、公式のGitリポジトリgit.sheetjs.comで開発されているOSSで、ライセンスはApache 2.0です。READMEは目的を、複雑な表計算ファイルから有用なデータを取り出すことと、古いソフトでも新しいソフトでも開けるファイルを作ることの2つと説明しています。
最新は0.20.3、npmのxlsxは2022年の0.18.5で止まり脆弱性2件が未修正
リポジトリのタグを見ると、最新の正式版は2024年7月18日のv0.20.3です。開発は続いており、2026年2月9日にもsheet_to_htmlのリンク無害化オプションを足すコミットが入っています。
ところが、npmレジストリのlatestは0.18.5のままで、公開日は2022年3月24日です。公式ドキュメントのNode.jsのインストール手順は、レジストリ側の版が古いことを明記し、正式な配布元は公式CDNだとしています。それでもnpmの集計では、2026年10月23日〜29日の1週間に約1,546万回、古い0.18.5がダウンロードされています。
| 脆弱性 | 影響する版 | npmの0.18.5 |
|---|---|---|
| CVE-2023-30533(プロトタイプ汚染) | 0.19.3未満 | 該当・npmに修正版なし |
| CVE-2024-22363(ReDoS) | 0.20.2未満 | 該当・npmに修正版なし |
どちらもGHSA-4r6h-8v6p-xvw6とGHSA-5pgg-2g8v-p4x9として登録され、修正版がnpmに無いためnpm auditは解消手段を示せません。外部から受け取ったファイルを読む処理では、0.18.5のまま使い続ける理由はありません。正規表現の処理時間が膨らむ仕組みはReDoSの仕組みと実測で詳しく扱っています。
無償版でできることとPro限定の機能:書式・画像・グラフ・数式の計算
Community Editionが得意とするのは、値の取り出しと形式の変換です。逆に、見た目を作り込む機能の多くはSheetJS Proの製品ページに並んでいます。
| やりたいこと | Community Edition | Pro |
|---|---|---|
| xlsx・xls・CSVの読み込み | 対応 | 対応 |
| 表示形式・列幅・セル結合 | 対応 | 対応 |
| フォント・罫線・塗りつぶし | 対象外 | Pro Basic |
| 画像・グラフ | 対象外 | Pro Image・Pro Chart |
| 数式の計算 | 対象外 | 別製品のFormula Calculator |
Proの価格は製品ページに載っておらず、メールか打ち合わせで問い合わせる形です。見積もりを取る前に、書式付きの出力が本当に要るのかを画面の要件から確かめておくと、OSSの組み合わせで済むかどうかを早く判断できます。
Node.jsでの導入:CDNのtgzとExcel明細のJSON変換手順
ここからは、取引先が送ってくる受注一覧のxlsxを読み、DBに入れる前の配列に変換する例で手順を追います。コードは公式ドキュメントの記法に沿って組んだもので、Node.jsの現行LTSを想定しています。
npm iでCDNのtgzを指定し、overridesとvendor保存で版を固定する
すでにxlsxが入っているなら、いったん外してからCDNのURLで入れ直します。他のパッケージが依存としてxlsxを引き込んでいる場合は、package.jsonのoverridesで解決先を差し替えます。
npm rm --save xlsx
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
// package.json(依存先が古いxlsxを引き込むときの差し替え)
{
"overrides": {
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
}
}
公式ドキュメントは、tgzをダウンロードしてリポジトリのvendorフォルダに置き、file:vendor/xlsx-0.20.3.tgzで入れる方法も勧めています。CDNが止まってもビルドが通り、どの版が入っているかをコードレビューで確かめられます。CIでの依存の自動更新を入れているなら、URL指定の依存は更新の対象外になる点に注意してください。自動更新の仕組みはDependabotとGitHub Actionsの連携設定にまとめています。
readFileとsheet_to_jsonによる明細取込と列・範囲・空欄の指定
明細を取り出すコードでは、headerで列名、rangeで読込範囲、defvalで空欄の扱いを指定します。CommonJSならrequire('xlsx')だけでファイル読み込みも使えます。ESMで読み込む場合は、XLSX.set_fs(fs)でfsモジュールを渡す必要があり、ここで詰まる人が多い箇所です。両方式の違いはESMとCommonJSの違いと移行手順を参照してください。
const XLSX = require('xlsx');
const wb = XLSX.readFile('./orders.xlsx', {
sheets: '受注', // 使うシートだけ解析する
cellDates: true, // 日付セルを Date で受け取る
});
const ws = wb.Sheets['受注'];
// 1行目は取引先ごとに表記が揺れる見出しなので使わず、キーを自分で決める
const rows = XLSX.utils.sheet_to_json(ws, {
header: ['orderId', 'client', 'orderDate', 'qty', 'amount'],
range: 1, // 2行目から読む
defval: null, // 空セルもキーを残す
});
for (const r of rows) {
if (!r.orderId) continue; // 合計行や空行を飛ばす
console.log(r.orderId, r.orderDate, Number(r.amount));
}
sheet_to_jsonのオプションでは、headerを省くと1行目がキーになり、配列で渡すとその名前がキーになります。defvalを指定しないと空セルのキーが消えるため、DBに入れる前の検証で「列が無い」と「値が空」を区別できません。rawは既定でtrueで、表示形式を通さない値が返ります。画面と同じ文字列が欲しいときだけfalseにします。
日付が数値で返る・1日ずれる問題はcellDatesとUTCオプションで揃える
Excelは日付を、基準日からの日数を表す数値で持っています。読み込みオプションの一覧のとおりcellDatesの既定はfalseなので、指定しないと日付セルは45961のようなシリアル値で返ります。上のコードでtrueにしているのはこのためです。
もう一つの落とし穴はタイムゾーンです。日付と時刻の解説ページによると、Excelの日付は絶対時刻を表せず、ファイルを作った環境の時計に依存します。SheetJSは0.20.0で日付の処理を大きく作り直しており、sheet_to_jsonなどで指定できるのがUTCオプションです。指定するとUTCとして、しないと実行環境のローカル時刻として解釈されます。
サーバーをUTCで動かし、取引先は日本時間で入力したファイルを送ってくる構成では、0時ちょうどの日付が前日に見えることがあります。対処は2つです。日付だけの列なら、Dateに直さずにYYYY-MM-DDの文字列へ変換してから扱う方法、またはUTCオプションを明示してサーバーとブラウザで解釈を揃える方法です。どちらにしても、実際の取引先ファイルを数件読ませて、DBに入る日付を目で突き合わせてから本番に出します。
ブラウザでの読み書き:Excelの画面解析と一覧のxlsxダウンロード実装
SheetJSはブラウザでも同じAPIで動くため、サーバーにファイルを送らずに中身をプレビューしたり、表示中の一覧をその場でxlsxにしたりできます。
file.arrayBuffer()で読み、数万行を超えたらWeb Workerへ移す
ブラウザ向けにはスタンドアロン版の配布ページにscriptタグ用のxlsx.full.min.jsとESM用のxlsx.mjsがあります。公式は、CDNから直接読むより自社サーバーに置く方法を勧めています。
<input type="file" id="upload" accept=".xlsx,.xls,.csv">
<script type="module">
import * as XLSX from '/vendor/xlsx-0.20.3/xlsx.mjs'; // 自社サーバーに置いたコピー
document.getElementById('upload').addEventListener('change', async (e) => {
const file = e.target.files[0];
const wb = XLSX.read(await file.arrayBuffer(), { dense: true, sheetRows: 1001 });
const ws = wb.Sheets[wb.SheetNames[0]];
const preview = XLSX.utils.sheet_to_json(ws, { defval: '' });
console.log(`先頭${preview.length}件を表示`, preview[0]);
});
</script>
プレビューだけならsheetRowsで読む行数を絞れます。見出し行を含むため、1001を指定するとJSONは1,000件です。全件の解析はメインスレッドで動くため、数万行のファイルでは解析が終わるまで画面の操作を受け付けません。そうした件数を扱う画面では、解析をWeb Workerで別スレッドに移す実装にしておくと操作が止まりません。
json_to_sheetとwriteFileXLSXによる列幅・表示形式付き出力
列幅は!cols、表示形式はzで指定する書き出し例です。配列からシートを作るにはjson_to_sheetを使い、ブラウザでwriteFile系を呼ぶとダウンロードが始まります。xlsxしか出さない画面なら、形式を絞ったwriteFileXLSXを使うと読み込むコードを小さくできます。
const rows = [
{ 請求番号: 'INV-0001', 取引先: '株式会社サンプル', 金額: 132000 },
{ 請求番号: 'INV-0002', 取引先: '有限会社テスト', 金額: 88000 },
];
const ws = XLSX.utils.json_to_sheet(rows);
ws['!cols'] = [{ wch: 12 }, { wch: 24 }, { wch: 12 }]; // 列幅(文字数)
for (let r = 1; r <= rows.length; r++) { // 0行目は見出し
const cell = ws[XLSX.utils.encode_cell({ r, c: 2 })];
if (cell) cell.z = '#,##0'; // 金額に桁区切り
}
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, '請求一覧');
XLSX.writeFileXLSX(wb, '請求一覧_202610.xlsx', { compression: true });
表示形式はセルのzに書く、と表示形式の解説ページにあります。書き出しオプションのcompressionは既定でfalseで、速度を優先してファイルが大きくなります。メールで送られる帳票なら、trueを指定する運用です。ここまでが無償版で整えられる範囲で、見出しを太字にする・罫線を引くといった指定は書き出されません。
大量データ:dense・sheetRows・streamの選択とxlsx出力の限界
SheetJSは、読み込みも書き出しもファイル全体をメモリに展開してから処理します。10万行を超える取込やエクスポートでは、この前提を踏まえた設計が要ります。
読み込みはsheets・sheetRows・denseで解析範囲を絞り、全体読みを避ける
読み込み側で使えるのは、解析範囲を狭める3つのオプションです。sheetsで必要なシートだけを指定し、sheetRowsで行数に上限を設け、denseでセルを配列の配列として持たせます。denseは0.19.0で全面的に作り直された形式で、後方互換のため既定では無効です。
ストリーミングでの読み込みは、大規模データの解説ページに記載がありません。数十MBのxlsxを毎日受け取るような取込は、ファイルの受付と解析を分け、解析をキューの先で動かす構成にします。S3とキューで取込を分ける設計はCSV一括インポートをLambdaとSQSで実装する方法が参考になります。
書き出しのストリーミングはCSV・JSON・HTML・XMLの4種、xlsxは対象外
ストリーミングの書き出し関数はXLSX.stream.to_csv・to_json・to_html・to_xlml(SpreadsheetML 2003形式)の4つで、xlsxを少しずつ書く関数はありません。
const XLSX = require('xlsx');
const fs = require('fs');
// 最初のシートだけを dense で読み、CSV へ少しずつ流す
const wb = XLSX.readFile('./big.xlsx', { dense: true, sheets: 0 });
const ws = wb.Sheets[wb.SheetNames[0]];
XLSX.stream.to_csv(ws).pipe(fs.createWriteStream('./big.csv'));
この方法で減らせるのは出力時のメモリだけで、読み込みは全体を展開します。サーバーで数十万行のxlsxを書式付きで出す要件なら、行ごとに確定して書き出せるExcelJSのストリーミングWriterか、GoのExcelizeのほうが向いています。HTTPで返す部分の書き方はExpress.jsの入門と5系への移行点を参照してください。
SheetJSを業務システムで採用する条件と見送る場面、ExcelJSとの使い分け
機能だけで見れば、JavaScriptで読める形式の多さはSheetJSが抜けています。判断を分けるのは、配布元がnpmの外にあることを運用で吸収できるかと、出力に書式が要るかの2点です。
採用する条件:取込と形式変換が主で、CDN版を固定して監視できる
採用してよいのは、Excelから値を取り出してDBに入れる取込、xlsとxlsxとCSVが混ざる受付、画面の一覧を表示形式だけ整えて出すエクスポートです。どれも無償版の範囲で完結します。
そのうえで、tgzをvendorに置いて版を固定し、git.sheetjs.comのタグを四半期ごとに確認する運用を入れます。npmの通知が来ないので、更新に気づく仕組みは自前で持つしかありません。受け付けるファイルにはサイズの上限を設け、解析はWorkerや別プロセスで時間とメモリを制限して動かします。Excelの取込や出力を含む業務システムを新しく作る、または古い取込処理を作り直す場合は、業務用・Webアプリ開発としてご相談いただけます。
見送る場面:書式付き帳票の出力と、npm版から上げられない既存環境
見送るのは2つの場面です。1つ目は、罫線や色で整えた請求書・報告書をExcelで出す要件です。無償版では書式が出ないため、Proを契約しないなら出力はExcelJSで書きます。
2つ目は、社内の規程でnpmレジストリ以外からの依存の取得が認められていない環境です。この場合に入るのは0.18.5だけで、利用者がアップロードするファイルを読む処理には使えません。取込を社内で作ったファイルに限るか、CSVでの受付に切り替えるか、別のライブラリにするかを決めてから実装に入ります。
ExcelJSとの比較:読める形式の多さか、書式の再現かで選ぶ
Node.jsでExcelを扱う候補は、実質的にSheetJSとExcelJSの2つです。どちらも配布や保守に癖があるので、強みで分けて併用する構成も現実的です。
| 観点 | SheetJS(無償版) | ExcelJS |
|---|---|---|
| 版と配布(2026年11月) | 0.20.3・公式CDN | 4.4.0(2023年10月)・npm |
| 読める形式 | xlsx・xls・CSVほか多数 | xlsxとCSV |
| フォント・罫線の書き出し | 対象外(Pro) | 対応 |
| xlsxのストリーミング書き出し | なし | WorkbookWriterで対応 |
| ライセンス | Apache 2.0 | MIT |
受付はSheetJSで多形式を吸収し、書式付きの帳票出力ならExcelJS、という分担が一つの答えです。ExcelJSの帳票コードと保守状況はExcelJSの使い方と10万行の出力、保守停止の注意点で詳しく扱っています。
よくある質問
SheetJSを使い始める前に確認されることの多い質問をまとめました。
SheetJSは無料で商用利用できますか?
Community Editionはできます。ライセンスはApache 2.0で、商用のシステムに組み込んでも費用はかかりません。条件は、配布するときにライセンス文と著作権表示を含めることで、改変したファイルにはその旨を示します。社内のサーバーで動かすだけなら配布にあたらないことが多いものの、パッケージにして納品するときは、利用しているOSSの一覧と一緒にライセンス文を添えておくと後の確認が楽になります。
npm install xlsxで入る版をそのまま使ってもよいですか?
勧めません。入るのは2022年3月の0.18.5で、プロトタイプ汚染(CVE-2023-30533)とReDoS(CVE-2024-22363)の2件が未修正です。社内で作った固定のファイルだけを読む処理なら影響は限られますが、利用者がアップロードするファイルを読むなら、CDNの0.20.3へ入れ替えます。依存先のパッケージが古いxlsxを引き込んでいる場合は、package.jsonのoverridesで差し替えられます。
SheetJSでセルの色や罫線を付けられますか?
無償のCommunity Editionでは付けられません。書き出せるのは値・表示形式・列幅・セル結合などで、フォント・罫線・塗りつぶしはSheetJS Proの機能です。GitHubやnpmには書式を書き出せるように改変した非公式のフォークもありますが、元の開発元とは無関係の配布で、更新が止まっているものもあります。書式が要るなら、Proを契約するか、出力だけExcelJSに分けるのが確実です。
SheetJSで古いxls形式のファイルは読めますか?
読めます。Excel 97〜2003形式のxlsも、xlsxと同じXLSX.readやreadFileで開けます。ExcelJSが扱えないxlsが混ざる取込でSheetJSが選ばれる理由の一つです。CSVやShift_JISのテキストを読むときは、文字コードの表をESMではset_cptableで渡す必要があります。取込の受付で形式を判定せずに済むので、利用者に保存し直しを頼む手間も減ります。
SheetJSは数式の計算結果を取得できますか?
Excelがファイルに保存した計算結果なら取得できます。セルのvに結果、fに数式の文字列が入ります。一方で、SheetJS自身は数式を計算しません。プログラムで値を書き換えた後の結果が欲しい場合、公式の選択肢は別製品のFormula Calculatorです。Excel以外のツールで作られたファイルは計算結果が保存されていないこともあるため、取込では空欄になる可能性を前提に検証を組みます。
関連記事
- Node.jsとは?仕組み・版の選び方・標準機能で動かす手順を実装目線で解説:SheetJSを動かすNode.jsの版の選び方です。
- Excelizeとは?GoでExcelを読み書きする使い方とv2.11.0の変更点・10万行の実測:Goで大量行のExcelを出す場合の比較材料です。
- ClosedXMLとは?C#でExcelを操作する使い方・できないこと・ライセンス【0.105.1】:.NETで同じ処理を組むときの選択肢です。
- 帳票電子化の進め方:出力・配信・保存の順序と電子帳簿保存法の要件【2026年時点】:Excelの取込と出力を業務全体の要件から考える記事です。
- ExcelJSとは:Node.jsでExcel帳票を作る使い方と10万行の出力、保守停止の注意点【2026年11月】:書式付き帳票をNode.jsで出す場合の実装です。