# Agora RTC — Next.js / SSR
The Agora Web SDK (`agora-rtc-sdk-ng`) and `agora-rtc-react` are browser-only. They cannot run during server-side rendering and will throw errors if imported at the module level in a Next.js Server Component or during SSR.
## The Problem
`next/dynamic` with `ssr: false` works in Pages Router and in Client Components, but **does NOT work in Server Components** in Next.js 14+ App Router. A Server Component importing a dynamically-loaded client module that references Agora will still fail at build time if the import is not properly isolated.
## Pattern: Wrap Both the Provider and Component
The correct pattern for Next.js App Router is to dynamically import both your Agora component **and** the `AgoraRTCProvider` together, inside a Client Component:
```tsx
'use client';
import { useMemo, Suspense } from 'react';
import dynamic from 'next/dynamic';
// Dynamically import your RTC component with ssr disabled
const ConversationComponent = dynamic(() => import('./ConversationComponent'), {
ssr: false,
});
// Dynamically import AgoraRTCProvider and create the client inside the same
// dynamic boundary — this keeps all Agora imports out of the SSR bundle
const AgoraProvider = dynamic(
async () => {
const { AgoraRTCProvider, default: AgoraRTC } =
await import('agora-rtc-react');
return {
default: ({ children }: { children: React.ReactNode }) => {
const client = useMemo(
() => AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8' }),
[],
);
return {children};
},
};
},
{ ssr: false },
);
export default function Page() {
return (
Loading...}>
);
}
```
**Why this works:** Both `AgoraRTCProvider` and `AgoraRTC.createClient` are inside the dynamic import callback, so they only execute in the browser. The `useMemo` ensures the client is created once per component mount, not on every render.
## Pattern: Simple Component Lazy Load (Pages Router / Client Components)
If you're in a Pages Router context or inside an existing `"use client"` boundary, the simpler pattern works:
```tsx
'use client';
import { useState, useEffect } from 'react';
export default function Page() {
const [VideoCall, setVideoCall] = useState(null);
useEffect(() => {
import('./VideoCall').then((m) => setVideoCall(() => m.default));
}, []);
if (!VideoCall) return Loading...
;
return ;
}
```
## Key Rules
- Mark any component that imports Agora with `"use client"`.
- Never import `agora-rtc-sdk-ng` or `agora-rtc-react` at the top level of a Server Component.
- Create the `AgoraRTC.createClient` instance inside a `useMemo` (or outside the component tree) — never in the render function directly.
- Wrap dynamic-loaded Agora components in `` to handle the async load state.
## Node.js Version Requirements
- Next.js 14 / 15: requires Node.js >= 18
- Next.js 16+: requires Node.js >= 20.9.0 (used in agent-samples clients)