Polotno Docs
Getting started

Next.js

Use Polotno Design Editor in a Next.js app (App Router)

How to use Polotno Design editor with Next.js?

Demo repository: polotno-next

1) Install dependencies

npm install polotno canvas

2) Create an Editor component (client-only)

Create components/editor.tsx. Do not place it inside pages or app to avoid server-side rendering.

import React from 'react';
import { PolotnoContainer, SidePanelWrap, WorkspaceWrap } from 'polotno';
import { Toolbar } from 'polotno/toolbar/toolbar';
import { PagesTimeline } from 'polotno/pages-timeline';
import { ZoomButtons } from 'polotno/toolbar/zoom-buttons';
import { SidePanel } from 'polotno/side-panel';
import { Workspace } from 'polotno/canvas/workspace';

import { createStore } from 'polotno/model/store';

const store = createStore({
  key: 'YOUR_API_KEY', // create an API key at https://polotno.com/cabinet/
  // you can hide back-link on a paid license
  // but it will be good if you can keep it for Polotno project support
  showCredit: true,
});
store.addPage();

export const Editor = () => {
  return (
    <PolotnoContainer style={{ width: '100vw', height: '100vh' }}>
      <link
        rel="stylesheet"
        href="https://unpkg.com/@blueprintjs/core@5/lib/css/blueprint.css"
      />
      <SidePanelWrap>
        <SidePanel store={store} />
      </SidePanelWrap>
      <WorkspaceWrap>
        <Toolbar store={store} downloadButtonEnabled />
        <Workspace store={store} />
        <ZoomButtons store={store} />
        <PagesTimeline store={store} />
      </WorkspaceWrap>
    </PolotnoContainer>
  );
};

export default Editor;

3) Use dynamic import in a client component

'use client';

import dynamic from 'next/dynamic';
const Editor = dynamic(() => import('../components/editor'), {
  ssr: false,
});

export default function Home() {
  return <Editor />;
}

Next.js 15

Add the following to your package.json and reinstall dependencies.

{
  "overrides": {
    "polotno": {
      "react": "^19",
      "react-dom": "^19",
      "react-konva": "^19.0.3"
    }
  }
}

For pnpm:

{
  "pnpm": {
    "overrides": {
      "polotno>react": "^19",
      "polotno>react-dom": "^19",
      "polotno>react-konva": "19.0.3"
    }
  }
}

Config (outdated)

Note: these configs were required in previous versions of Next.js. We keep them here temporarily for reference.

If you use the App Router with Webpack, put this into next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    config.externals = [...config.externals, { canvas: 'canvas' }]; // required to make Konva & react-konva work
    return config;
  },
};

module.exports = nextConfig;

If you use Turbopack, you may need to create an empty file called empty.js and use this config to disable canvas module loading:

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    turbo: {
      resolveAlias: {
        canvas: { browser: './empty.js' },
      },
    },
  },
};

export default nextConfig;

Live demo