# Next.js

> Set up Fabric.js in Next.js without SSR errors: render the canvas editor in a client component with 'use client' and a dynamic import that skips the server.

Source: https://fabricjs-document-engine.jscrate.dev/docs/frameworks/next-js
Last updated: 2026-09-28

Fabric.js needs a browser: it creates `<canvas>` elements and reads `window`. In Fabric.js Next.js apps, render the editor only on the client, and keep the rest of the page server-rendered.

## Render the editor on the client

Put the editor in its own file marked `'use client'`, and load it with a dynamic import that skips SSR:

```tsx
// app/editor/editor-loader.tsx
"use client";

import dynamic from "next/dynamic";

export const Editor = dynamic(() => import("./editor-client"), {
  ssr: false,
  loading: () => <p>Loading the editor…</p>,
});
```

```tsx
// app/editor/page.tsx
import { Editor } from "./editor-loader";

export default function EditorPage() {
  return (
    <main>
      <h1>Floor plan</h1>
      <Editor />
    </main>
  );
}
```

`ssr: false` is only allowed inside a client component, which is why the loader file has `'use client'` too.

## The client component

Inside `editor-client.tsx`, create the canvas in an effect and use the hooks, exactly as in the [React guide](https://fabricjs-document-engine.jscrate.dev/docs/frameworks/react):

```tsx
// app/editor/editor-client.tsx
"use client";

import { useDocumentEngine } from "fabricjs-document-engine/react";
import { createLocalStorage } from "fabricjs-document-engine/storage";

import { useFabricCanvas } from "./use-fabric-canvas";

const storage = createLocalStorage({ prefix: "plans:" });

export default function EditorClient() {
  const { elementRef, canvas } = useFabricCanvas(1200, 800);
  const engine = useDocumentEngine(canvas, { storage, autosave: true });

  return <canvas ref={elementRef} aria-label="Floor plan editor" />;
}
```

The `fabricjs-document-engine/react` entry is already marked `'use client'`, so importing the hooks never breaks a server component.

## On the server

The document helpers work in Node without a canvas. Use them in a route handler to check uploads before you store them:

```ts
// app/api/documents/[id]/route.ts
import { secureDocument, validateDocument } from "fabricjs-document-engine";

export async function PUT(request: Request) {
  const document = secureDocument(await request.json());
  if (validateDocument(document).length > 0) {
    return new Response("Invalid document", { status: 422 });
  }
  // Store the document, checking the revision in the same query.
  return Response.json({ revision: 1 });
}
```

## Common Fabric.js Next.js errors

- **"window is not defined"**: Fabric.js ran during SSR. Load the editor with `ssr: false`.
- **"useState only works in client components"**: import hooks from `fabricjs-document-engine/react` inside a file marked `'use client'`.

More fixes are in [troubleshooting](https://fabricjs-document-engine.jscrate.dev/docs/production/troubleshooting).
