Node.jsでサーバーサイドのプログラムを開発していると、ログ出力やデータの蓄積のために既存のファイルへデータを追記したい場面が頻繁に登場します。

標準モジュールであるfs(File System)を使用すれば、ファイルを上書きすることなく、末尾に新しいテキストを簡単に追加することが可能です。

しかし、Node.jsには非同期処理のfs.appendFileと、同期処理のfs.appendFileSyncという2つの主要なメソッドが存在し、それぞれ適切な使い分けが求められます。

本記事では、これら2つのメソッドの具体的な使い方から、2026年現在の開発現場で主流となっているPromise(async/await)を活用したモダンな実装方法まで詳しく紹介します。

fs.appendFileによる非同期でのファイル追記

fs.appendFileは、Node.jsのノンブロッキングI/Oの特性を活かした、非同期で動作するメソッドです。

ファイルの読み書きが終わるのを待たずに次の処理を実行できるため、高負荷なWebサーバーなどでパフォーマンスを維持したい場合に最適な選択肢となります。

基本的な構文では、第一引数にファイルパス、第二引数に追記したいデータ、第三引数にコールバック関数を記述します。

もし指定したファイルが存在しない場合は、Node.jsが自動的に新規ファイルを作成してデータを書き込んでくれるため、事前の存在チェックは不要です。

JavaScript
const fs = require('fs');

// 追記するメッセージ
const message = '非同期でのログ出力テストです。\n';

// fs.appendFile(ファイル名, 追記データ, コールバック関数)
fs.appendFile('log.txt', message, (err) => {
  if (err) {
    console.error('エラーが発生しました:', err);
    return;
  }
  console.log('ファイルの追記が成功しました。');
});

console.log('appendFileの実行直後の処理です。');
実行結果
appendFileの実行直後の処理です。
ファイルの追記が成功しました。

実行結果を確認すると、コールバック関数内のメッセージよりも先に、プログラム末尾のコンソール出力が表示されていることが分かります。

これが「非同期処理」の特徴であり、重いファイル操作の完了を待たずにアプリケーション全体を動かし続けることができます。

fs.appendFileSyncによる同期でのファイル追記

一方で、fs.appendFileSyncはファイルへの追記が完了するまでプログラムの実行を一時停止する、同期型のメソッドです。

コードが上から順番に実行されるため、処理の流れを理解しやすく、コマンドラインツール(CLI)やバッチ処理などのシンプルなスクリプトで重宝されます。

非同期版と異なり、コールバック関数を必要としないため、コードが非常に短く読みやすくなるのがメリットです。

ただし、大容量のファイルを扱う際や、同時に多数のユーザーをさばくWebサーバーで使用すると、アプリ全体の動作を止めてしまう(ブロッキング)原因になるため注意が必要です。

JavaScript
const fs = require('fs');

try {
  const message = '同期処理による追記です。\n';
  
  // fs.appendFileSync(ファイル名, 追記データ)
  fs.appendFileSync('sync_log.txt', message);
  
  console.log('同期的な追記が完了しました。');
} catch (err) {
  console.error('エラーが発生しました:', err);
}

console.log('追記完了後の処理を開始します。');
実行結果
同期的な追記が完了しました。
追記完了後の処理を開始します。

実行結果を見ると、非同期版とは異なり、追記完了のメッセージが出た後に後続の処理が実行されていることが確認できます。

エラーハンドリングを行う際は、try...catch構文を使用する必要がある点に注意してください。

fs.appendFileとfs.appendFileSyncの比較表

開発シーンに応じてどちらを選択すべきか、以下の表で整理してみましょう。

特徴fs.appendFilefs.appendFileSync
処理方式非同期(ノンブロッキング)同期(ブロッキング)
パフォーマンス高い(他の処理を邪魔しない)低い(完了まで待機する)
推奨シーンWebアプリケーション、サーバー構築設定ファイル作成、CLIツール
エラー処理コールバックまたはPromisetry…catch

現代のNode.js開発においては、パフォーマンスと可読性を両立するために、後述するPromise版の使用が強く推奨されています。

【推奨】Promise(async/await)を活用した追記方法

現在のNode.jsにおいて最も一般的で推奨されるのが、fs.promisesを使用した実装です。

fs.appendFileの非同期性を維持しつつ、async/await構文を用いることで同期処理のような「読みやすいコード」を実現できます。

これにより、コールバック地獄を防ぎ、保守性の高いクリーンなコードを記述することが可能になります。

JavaScript
const fs = require('fs').promises;

async function appendLog(filename, data) {
  try {
    // awaitを使用することで非同期処理をスマートに記述
    await fs.appendFile(filename, data + '\n');
    console.log(`${filename} への追記が完了しました。`);
  } catch (err) {
    console.error('エラーが発生しました:', err);
  }
}

appendLog('modern_log.txt', 'Promiseベースの追記処理です。');

この書き方はエラーハンドリングもtry...catchで統一できるため、プロジェクトの規模が大きくなってもコードが複雑になりにくいという利点があります。

ファイル追記時に指定できるオプション

appendFileメソッドの第三引数(Promise版では第二引数のオブジェクト)には、エンコーディングやパーミッションなどのオプションを指定できます。

  • encoding: デフォルトは 'utf8' です。バイナリデータを扱う場合は 'binary' などを指定します。
  • mode: ファイルの権限(パーミッション)を設定します。デフォルトは 0o666 です。
  • flag: 書き込みモードを指定します。追記の場合はデフォルトで 'a' (append) が設定されています。
JavaScript
const fs = require('fs').promises;

async function advancedAppend() {
  await fs.appendFile('secure_log.txt', '権限指定付きの追記\n', {
    encoding: 'utf8',
    mode: 0o600, // 所有者のみ読み書き可能
    flag: 'a'
  });
}

大量のデータを追記する場合の注意点

ここまで紹介したメソッドは、ファイル全体を一度にメモリに読み込むわけではありませんが、短時間に数万回の追記を行うような場合には適していません。

もしリアルタイムで大量のログが流れてくるようなケースでは、「書き込みストリーム(Writable Stream)」を利用することを検討してください。

fs.createWriteStreamを使用し、フラグに 'a' を指定することで、ファイルとの接続を維持したまま効率的にデータを流し込むことができます。

JavaScript
const fs = require('fs');

// 書き込みストリームを作成(flags: 'a' で追記モード)
const stream = fs.createWriteStream('stream_log.txt', { flags: 'a' });

stream.write('ストリームによる1行目の追記\n');
stream.write('ストリームによる2行目の追記\n');

// 最後にストリームを閉じる
stream.end('書き込みを終了します。\n');

stream.on('finish', () => {
  console.log('すべての書き込みが完了しました。');
});

ストリームを利用することで、システムのリソース(メモリ)消費を最小限に抑えつつ、高速な連続書き込みが可能になります。

まとめ

Node.jsでファイルにデータを追記する際は、プログラムの用途に応じて最適なメソッドを選択することが重要です。

基本的には、「fs.promises.appendFile」と「async/await」を組み合わせる方法が、2026年の開発においても最も一般的でバランスの良い選択と言えます。

一方で、簡単なスクリプトや初期化処理であればfs.appendFileSyncが便利であり、膨大なデータを連続して書き込むならストリームを活用するべきです。

それぞれのメリットとデメリットを正しく理解し、エラーハンドリングを丁寧に行うことで、信頼性の高いNode.jsアプリケーションを構築していきましょう。