こんにちは!エンジニア&SiiD講師のセイトです。
VercelにNext.jsのアプリをデプロイする際、非効率なコーディングをしているとEMFILE Errorというビルドエラーに出くわすことがあります。
VercelのServerless Functionsでは、同時に開けるファイルの数(ファイルディスクリプタ数)に上限(通常1024)があり、それを超えると EMFILE: too many open files
エラーが発生します。
本記事では何が原因で、どう対策すればいいのかを8つのポイントに整理しました。お試しあれ!
1. 必要最小限のモジュールだけをインポートする
- 背景:不要なライブラリ全体をインポートすると、それだけで数十〜数百ファイルを開く可能性があり、リソースを圧迫します。
- 対応:ライブラリは関数単位やモジュール単位で絞ってインポートすること。
// 悪い例:lodash全体を読み込む
import _ from 'lodash'
// 良い例:必要な関数だけ読み込む
import debounce from 'lodash/debounce'
2. 重い初期化処理は関数スコープ外で一度だけ実行する
- 背景:リクエストごとにDB接続やライブラリ初期化を行うと、都度ファイルやソケットを開くことになり、上限を超えやすくなります。
- 対応:ファイルスコープにインスタンスをキャッシュし、Cold Start時のみ初期化するように構成します。
let cachedDb = null
async function connectToDatabase() {
if (cachedDb) return cachedDb
cachedDb = await someDb.connect(process.env.DB_URL)
return cachedDb
}
export default async function handler(req, res) {
const db = await connectToDatabase()
const user = await db.users.findOne({ id: 1 })
res.json(user)
}
3. 使っていないコードはバンドルに含めない(Tree Shakingの有効化)
- 背景:ビルド時に不要なモジュールまで含まれていると、実行時に読み込むファイル数も増加します。
- 対応:
package.json
に"sideEffects": false
を設定することで、使われていないコードの削除(Tree Shaking)を促進します。
{
"sideEffects": false
}
※ 副作用のあるファイル(CSSなど)は個別指定することで除外できます。
4. 動的インポートで後から必要な処理だけ読み込む
- 背景:全ての機能を初期ロード時に読み込むとバンドルが肥大化し、読み込みファイル数が増加します。
- 対応:
next/dynamic
を使って、特定のコンポーネントやモジュールは必要になったときにのみ読み込むようにします。
import dynamic from 'next/dynamic'
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <>Loading...<\/>,
ssr: false,
})
5. 依存ライブラリのサイズや構成を可視化して最適化する
- 背景:何がどのくらいのファイルを引き込んでいるかが見えないと、最適化が困難になります。
- 対応:
@next/bundle-analyzer
を導入し、バンドル内容を可視化して重いライブラリや不要な依存を特定します。
npm install @next/bundle-analyzer
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({ })
ANALYZE=true
npm run build
6. Preview環境で本番反映前に挙動と負荷を検証する
- 背景:Serverlessの実行時エラーは本番環境で初めて表面化することも多いため、事前検証が重要です。
- 対応:VercelのPull Request機能によるPreview URLで動作確認・アクセス負荷テストを実施しましょう。
7. devDependencies を本番ビルドに含めない
- 背景:開発専用ライブラリが本番にも含まれると、不要な依存ファイルが増えてEMFILEリスクが高まります。
- 対応:CI/CDやVercelのビルド設定で
npm install --production
を使用し、本番には必要最小限の依存のみを含めます。
# GitHub Actions 例
- name: Install Production Dependencies
run: npm install --production
8. Next.jsの optimizePackageImports
を活用してインポートを最適化
- 背景:特定ライブラリ(例:
myLibrary
)が数百の小ファイルを一括で読み込む構造になっており、EMFILEの温床になりやすいです。 - 対応:Next.jsの
optimizePackageImports
オプションで、使用箇所に応じたモジュールだけを効率的に取り込むようにします。
module.exports = {
experimental: {
optimizePackageImports: ['myLibrary']
}
}
最後に
これらの対策はどれも、「一度に開くファイルの数を減らす」ことが本質です。Vercelのようなサーバレス環境では、各リクエストの中で何が起きているかを意識し、最小限の読み込み・最大限の再利用を設計段階から考慮することが、安定稼働への鍵となります。
もし、
「プログラミングを体系的に学びたい」
「エンジニア転職を頑張りたい」
「独学に限界を感じてきた...」
「コミュニティで仲間と共に学びたい」
などと感じられたら、ぜひ検討してみてください。
まずは様子見...という方は、公式LINEにぜひご登録下さい。
学習や転職ノウハウに関する豪華特典11個を無料配布しています!
LINE紹介ページで特典を確認する