Next.js: サーバー専用のモジュールには import 'server-only' を書く
DB 呼び出しや API キーを扱う共有モジュールの先頭に import 'server-only' を書いておくと、Client Component からそのファイルを import した時点でビルドが失敗する。サーバーのコードや秘密情報が気づかないままブラウザ向けのバンドルに入るのを防げる。
何が起きるか
lib/db.ts のような共有ファイルは、Server Component から使っているうちは問題ない。ところが 'use client' のコンポーネントが(直接でも間接でも)それを import すると、ファイルごとクライアント向けにバンドルされる。NEXT_PUBLIC_ 以外の環境変数は空になるので動かないことが多いが、コードの中身やエンドポイントは配信されてしまう。
やり方
bash
npm install server-onlyts
// lib/db.ts
import 'server-only';
export async function getUser(id: string) {
const res = await fetch(`https://internal-api.example.com/users/${id}`, {
headers: { Authorization: `Bearer ${process.env.INTERNAL_API_KEY}` },
});
return res.json();
}- Client Component の依存関係にこのファイルが入ると、Next.js のビルド(と開発サーバー)がエラーで止まり、どこから import されたかが表示される。
- 逆向きの
import 'client-only'もあり、windowなどブラウザ専用のコードをサーバー側で読み込ませないようにできる。
注意点
server-onlyは「Client Component から import されたら失敗させる」だけの目印。Server Action の引数チェックや認可の代わりにはならない。- 環境変数は
NEXT_PUBLIC_を付けない限りクライアントには埋め込まれないが、server-onlyはコードそのものの混入も防ぐ点が違う。 - App Router(React Server Components)向けの仕組み。Pages Router のファイルでは区別がないので、この使い方はできない。
出典
- @itsthishanth · 2026-10-27
- Next.js ドキュメント(サーバー専用コードの混入を防ぐ): nextjs.org