> For the complete documentation index, see [llms.txt](https://docs.sealights.io/knowledgebase/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sealights.io/knowledgebase/setup-and-configuration/sealights-agents-and-plugins/node.js-agent/advanced-features/next.js-with-sealights-node-and-browser-agents-multi-module-scan.md).

# Next.js with SeaLights Node.js and Browser Agents (Multi-Module Scan)

## Next.js with SeaLights Node and Browser Agents (Multi-Module Scan)

> Next.js applications **require two scans** of the same build session: one for the browser bundles in `.next/static/` and one for the server-side bundles in the remainder of `.next/`. The browser bundles are instrumented at build time, while server-side coverage is collected using the SeaLights Node.js runtime preload.
>
> **Requires:** `slnodejs`  6.2.10 or later

### Overview

Next.js produces two distinct types of bundles during a production build. SeaLights processes each bundle type using a different instrumentation approach.

<table><thead><tr><th width="157.453125">Bundle</th><th width="169.83984375">Location</th><th>How SeaLights instruments it</th></tr></thead><tbody><tr><td><strong>Client (browser)</strong></td><td><code>.next/static/</code></td><td>Build-time scan with <code>--instrumentForBrowsers</code></td></tr><tr><td><strong>Server (Node.js)</strong></td><td>Remaining <code>.next/</code> output</td><td>Runtime coverage using the SeaLights Node.js preload via <code>-r .../slnodejs/lib/preload.js</code></td></tr></tbody></table>

Both scans use the **same build session** and are identified by different `--uniqueModuleId` values. This allows SeaLights to present the client and server coverage as a single application.

### Why Are Two Scans Required?

Next.js splits your code into two fundamentally different execution environments, each requiring a different instrumentation approach:

**Client bundles**&#x20;

`.next/static/` contains JavaScript that executes in the browser. SeaLights instruments these bundles during the build using:

```
--instrumentForBrowsers
```

**Server bundles**&#x20;

The remaining `.next/` output contains Node.js code executed on the server. SeaLights collects coverage for these modules at runtime using the Node.js preload:

```
-r ./node_modules/slnodejs/lib/preload.js
```

**One build session**

Both scans use the same build session:

```
--uniqueModuleId client--uniqueModuleId server
```

This allows SeaLights to associate the two sets of modules with the same application build.

{% hint style="danger" %}
**Important:** Do not reuse the same `--uniqueModuleId` for the client and server scans. Each scan must have a unique module ID, such as `client` and `server`.
{% endhint %}

***

### Prerequisites

Before you begin, ensure you have:

* A Node.js application using **Next.js 15 or later**.
* `slnodejs` **6.2.10 or later**.
* A SeaLights Agent Token.
* Permission to modify the application's `next.config.mjs`.
* A production build that generates source maps for both client and server bundles.

{% hint style="info" %}
**Note:** The `slnodejs` version requirement is important because the multi-module Next.js flow relies on functionality introduced/fixed in 6.2.10.
{% endhint %}

### Step 1 — Enable Source Maps in Next.js

Add both flags to `next.config.mjs`:

```js
/** @type {import('next').NextConfig} */
const nextConfig = {
  productionBrowserSourceMaps: true,
  experimental: { serverSourceMaps: true },
};

export default nextConfig;
```

{% hint style="danger" %}
**Important:** **Do not skip this step.** SeaLights uses the generated `.js.map` files to map runtime coverage hits back to your original source files. Without source maps the server will report **0% coverage**.
{% endhint %}

***

### Step 2 — Exclude Framework-Generated Files

Create `.slignore.generated` file in the **project root**:

```
webpack:/**
.next/**
```

This prevents framework-generated files from appearing in the SeaLights coverage tree and keeps the coverage view focused on application source code. Example, without `.slignore.generated` file the SeaLights coverage tree shows \~200 internal Next.js/webpack entries that obscure the actual `src/` code.

***

### Step 3 — Provision Your Agent Token

Place your SeaLights agent token in `sltoken.txt` at the project root.

{% hint style="danger" %}
**Important:** **Do not commit the token to source control.**&#x20;

Add the following entries to `.gitignore`:

```
sltoken.txt
buildSessionId
sl-debug.log
.next/
sl-dist/
node_modules/
```

{% endhint %}

***

### Step 4 — Build and Scan the Application

The script below executes the complete build → scan → start lifecycle.

```bash
#!/usr/bin/env bash
#
# End-to-end SeaLights flow for a Next.js SSR project:
#   1. Build the app (Next.js produces `.next/`)
#   2. Open a SeaLights build session
#   3. Scan client bundles (`.next/static/`)
#   4. Scan server bundles (the rest of `.next/`)
#   5. Mark the build session as complete
#   6. Start the server with the runtime preload so coverage is collected

set -euo pipefail

if [ ! -f sltoken.txt ]; then
  echo "ERROR: sltoken.txt not found in $(pwd)." >&2
  echo "       Copy sltoken.txt.example, paste your SeaLights agent token, then re-run." >&2
  exit 1
fi

# 1. Clean previous builds
rm -rf .next sl-dist

# 2. Build the Next.js app (production mode, source maps enabled in next.config.mjs)
npm install
npm run build

# 3. Open a build session
#    In CI, replace the timestamp with your commit SHA or build system ID.
BUILD_ID="$(date +%s)"
npx slnodejs config \
  --appname "<YOUR_APP>" \
  --branch main \
  --build "$BUILD_ID"

# 4. Client scan — instruments browser bundles into sl-dist/
#    and registers them as the "client" sub-module in the build session.
npx slnodejs scan \
  --workspacepath .next/static \
  --es6Modules \
  --scm none \
  --instrumentForBrowsers \
  --outputpath sl-dist \
  --useRelativeSlMapping \
  --newInstrumenter \
  --uniqueModuleId client

# Remove the un-instrumented client output so it is not re-scanned
# by the server pass. The instrumented copy in sl-dist/ is restored below.
rm -rf .next/static

# 5. Server scan — walks the rest of .next/ (server bundles only)
npx slnodejs scan \
  --workspacepath .next \
  --es6Modules \
  --scm none \
  --uniqueModuleId server

# 6. Finalise the build session (signals all sub-modules have been submitted)
npx slnodejs scanned --buildsessionidfile buildSessionId --ok

# 7. Restore the instrumented client bundles so Next.js serves them at runtime
mv sl-dist .next/static

# 8. Start the server with the SeaLights Node preload
#    This script does NOT open or close a test session — see Step 5.
NODE_DEBUG=sl \
SL_LOG_LEVEL=debug \
NODE_OPTIONS='-r ./node_modules/slnodejs/lib/preload.js' \
npm run start
```

Replace `<YOUR_APP>` with your SeaLights application name. In CI, replace `--branch main` and `--build "$BUILD_ID"` with your real branch name and build identifier (e.g. the commit SHA).

***

### Step 5 — Open a Test Session, Exercise the App, Then Close It

After the server starts (Step 4), open a test stage from a **separate terminal** in the same project directory. This associates all incoming coverage data with the correct test stage on the dashboard.

```bash
# Open a test stage
npx slnodejs start --testStage Manual --buildSessionIdFile buildSessionId

# Run your tests or exercise your application: browser clicks, curl calls, your e2e suite, etc.

# Close the test stage — flushes pending footprints and finalises the test stage
npx slnodejs end --buildSessionIdFile buildSessionId
```

{% hint style="info" %}
The test stage lifecycle is intentionally separate from the build/scan/start script. This lets you run multiple test passes (`Manual`, `RegressionSuite`, etc.) against the same running server without rebuilding or re-scanning the application.
{% endhint %}

***

### Step 6 — Verify Coverage on the Dashboard

1. Stop the server (`Ctrl+C`).
2. Wait for data ingestion to complete.
3. Open the SeaLights coverage dashboard.
4. Select the application and build created in Step 4.&#x20;
5. Expand the build to see the **Manual** test stage.
6. Verify that both client-side and server-sde source files contain coverage.

> The coverage tree should show your application source files with coverage collected from both the browser and server execution environments.

***

### Troubleshooting

<table><thead><tr><th>Symptom</th><th width="192">Possible Cause</th><th>Resolution</th></tr></thead><tbody><tr><td><code>src/</code> shows 0% coverage</td><td>Source maps not enabled or are not available during the scan</td><td>Add <code>productionBrowserSourceMaps</code> and <code>serverSourceMaps</code> flags to <code>next.config.mjs</code>.</td></tr><tr><td><code>webpack:/</code> or <code>.next/</code> folders appear in coverage tree</td><td> <code>.slignore.generated</code> is missing or not being loaded</td><td>Create <code>.slignore.generated</code> in the project root and ensure <code>slnodejs</code> is 6.2.10 or later.</td></tr><tr><td><code>lib/</code> or <code>layout.tsx</code> stay at 0% even though pages are covered</td><td>Older <code>slnodejs</code> version or source-map resolution issue</td><td>Upgrade to <code>slnodejs</code> 6.2.10 or later.</td></tr><tr><td><code>/api/...</code> routes show 0% coverage</td><td>Routes are never called implicitly by Next.js</td><td>Explicitly call the API routes using your tests or tools such as <code>curl</code>.</td></tr><tr><td><code>sltoken.txt not found</code></td><td>The agent token file is missing from the project root</td><td>Create <code>sltoken.txt</code> and add the SeaLights Agent Token.</td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sealights.io/knowledgebase/setup-and-configuration/sealights-agents-and-plugins/node.js-agent/advanced-features/next.js-with-sealights-node-and-browser-agents-multi-module-scan.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
