Skip to content
Latchkey

How to Replace node-canvas with a CI-Friendly Alternative

node-canvas compiles against Cairo, Pango, and Pixman, so slim runners break on missing headers. The reliable fix is often to switch to an engine-bundling alternative.

The classic canvas (node-canvas) package builds a C++ addon against Cairo, Pango, Pixman, and JPEG dev libraries - a frequent CI failure when those system packages are absent. When you do not need node-canvas-specific APIs, a Skia-based alternative that bundles its engine removes the system-library build entirely.

Why it fails in CI

  • node-canvas needs libcairo2-dev, libpango1.0-dev, libjpeg-dev, libgif-dev - slim/Alpine images lack them → fatal error: cairo.h.
  • A source build also needs python3 + g++; missing on minimal images.
  • Alpine/musl has limited prebuilt coverage, forcing a heavy source build.

Install it reliably

Either install node-canvas system libraries, or migrate to an engine-bundling alternative. @napi-rs/canvas (Skia, N-API) and skia-canvas ship prebuilt binaries with no Cairo/Pango requirement and are the lowest-friction CI choice.

Terminal
# Option A: keep node-canvas (Debian/Ubuntu system libs)
apt-get update && apt-get install -y \
  build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
npm ci

# Option B: migrate to a bundled-engine alternative (no system libs)
npm install @napi-rs/canvas    # or: npm install skia-canvas

Cache & speed

For node-canvas, cache ~/.npm + ~/.cache/node-gyp and bake the Cairo/Pango libs into a custom image. For the alternatives there is nothing to compile - caching ~/.npm is enough.

.github/workflows/ci.yml
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

Common errors

  • fatal error: cairo.h: No such file or directory → install the Cairo/Pango dev libs, or switch to a bundled-engine alternative.
  • Package pangocairo was not found (pkg-config) → install libpango1.0-dev.
  • Heavy source build on Alpine → use @napi-rs/canvas/skia-canvas instead.

Key takeaways

  • node-canvas needs Cairo/Pango/Pixman/JPEG dev libs plus a C++ toolchain.
  • Engine-bundling alternatives (@napi-rs/canvas, skia-canvas) skip the system-library build.
  • Bake the system libs into the image if you must keep node-canvas.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →