Guides: Next.js: Keep server code out of client components with the nextjs preset, which follows chains of imports from each 'use client' file. # Next.js > Keep server code out of client components with the nextjs preset, which follows chains of imports from each 'use client' file. This guide keeps server-only code out of the browser in a Next.js app, with the `nextjs` preset. ## Before you start * Read [Getting started](/archangel/start/getting-started/). * You have a Next.js app that uses the App Router and `'use client'` files. ## What the preset checks A file that starts with `'use client'` runs in the browser. So does each file that it reaches through runtime imports. The preset refuses a chain of imports from a client file to the package `server-only` or to a Node built-in module, such as `node:fs`. A chain stops at a file that starts with `'use server'`. Next.js changes an import of a server action into a network call, so the code of the action does not go to the browser. The preset has one rule, `nextjs/client-stays-client`. It counts only runtime imports, because the compiler removes an `import type`. ## Add the preset The example app has a cart page, a client button, and a module that reads the cart from disk: * archangel.config.ts * tsconfig.json * app/ * cart/ * actions.ts * page.tsx * components/ * cart-button.tsx * lib/ * cart.ts * format.ts 1. Put the preset in `extends`: archangel.config.ts ```ts import { defineConfig, nextjs } from '@enhance-eng/archangel'; export default defineConfig({ extends: [nextjs()], }); ``` `nextjs()` checks the whole repository. To check one app of a monorepo, give its folder: `nextjs({ root: 'apps/web' })`. 2. Check the app: Terminal ```ansi $ npx archangel check error[may-not-import]: components/cart-button.tsx reaches server-only through components/cart-button.tsx → lib/format.ts → lib/cart.ts → server-only --> components/cart-button.tsx:3:29 | 3 | import { formatTotal } from '@/lib/format'; | ^^^^^^^^^^^^^^ remove an import of the chain, or move what the file needs into code that does not reach it | = note: rule: nextjs/client-stays-client = note: reason: Code that runs in the browser cannot use server-only code or Node built-in modules. = note: see: https://nextjs.org/docs/app/getting-started/server-and-client-components checked 6 files and 9 imports: 1 problem For what a code means, run `archangel docs may-not-import`. ``` The button is a client component. It imports `lib/format.ts` to format the total. `format.ts` imports `lib/cart.ts` for one constant, and `cart.ts` imports `server-only`. So the button pulls server code into the browser. The error shows the full chain. These are the files of the chain: components/cart-button.tsx ```tsx 'use client'; import { checkout } from '@/app/cart/actions'; import { formatTotal } from '@/lib/format'; export function CartButton({ total }: { total: number }) { return ; } ``` lib/format.ts ```ts import { currency } from './cart'; export function formatTotal(cents: number): string { return `${currency} ${(cents / 100).toFixed(2)}`; } ``` lib/cart.ts ```ts import 'server-only'; import { readFile } from 'node:fs/promises'; export const currency = 'USD'; export async function cartTotal(): Promise { return Number(await readFile('cart.txt', 'utf8')); } export async function saveCart(): Promise {} ``` The button also imports `checkout` from `app/cart/actions.ts`, which also imports `lib/cart.ts`. The rule does not refuse that chain, because `actions.ts` starts with `'use server'`. ## Fix the chain 1. Move the constant into `format.ts`, so that `format.ts` imports nothing from the server: lib/format.ts ```ts export const currency = 'USD'; export function formatTotal(cents: number): string { return `${currency} ${(cents / 100).toFixed(2)}`; } ``` 2. Check again: Terminal ```ansi $ npx archangel check checked 6 files and 8 imports: no problems ``` ## Find a chain yourself `archangel why` shows the shortest chain of imports from one file to a file or a package: Terminal ```ansi $ npx archangel why components/cart-button.tsx server-only components/cart-button.tsx:2 imports '@/app/cart/actions' app/cart/actions.ts:2 imports '@/lib/cart' lib/cart.ts:1 imports 'server-only' server-only ``` why does not know where a rule stops `why` shows the shortest chain of all imports. This chain goes through `app/cart/actions.ts`, a `'use server'` file, so the preset rule does not refuse it. Use `why` to see how code connects. Use `archangel check` to see what a rule refuses. ## Prove the preset Terminal ```ansi $ npx archangel test pass nextjs/client-stays-client accepted #1 app/example-actions.ts, app/example-page.tsx pass nextjs/client-stays-client rejected #1 app/example-helper.ts, app/example-page.tsx 2 examples, none failed; 0 rules without a rejected example ``` The preset brings its own examples: one client page that reaches `node:fs` through a helper, and one that reaches it only through a `'use server'` file. ## Next steps * [Presets](/archangel/reference/presets/) lists the options of `nextjs`. * [Conditions](/archangel/reference/conditions/) tells you how to write your own rule about chains of imports, with `transitively` and `stopAt`.