← Back to list

Mixing C++ with JavaScript in Node.js | When and How to Use Native Addons

JavaScript is great for writing business logic and building applications quickly. But when performance matters, heavy computation, image…

Shehzad Ahmed · 2025-11-05 08:23 · 11 claps · 2.8 min read
#javascript #c-language #programming
Open on Medium ↗
Wiki topics: 💻 · Programming 🌐 · Web Development

Mixing C++ with JavaScript in Node.js | When and How to Use Native Addons

JavaScript is great for writing business logic and building applications quickly. But when performance matters, heavy computation, image processing, cryptography, scientific math, JavaScript alone may not cut it.

That’s where Node.js Native Addons come in.

Mixing C++ with JavaScript in Node.js | When and How to Use Native Addons

Mixing C++ with JavaScript in Node.js | When and How to Use Native Addons

Native Addons allow us to write high-performance code in C++ and call it directly from Node.js as if it were regular JavaScript. This is especially useful when:

  • You have performance-critical logic
  • You want to reuse existing C++ libraries
  • You need access to low-level system functionality

In this article, we’ll walk through how to call C++ from Node.js using N-API and then build a real-world performance example.

Why N-API?

There are several ways to connect C++ with Node: NAN, FFI, WebAssembly, etc. But N-API is the modern and stable solution because:

✅ API stays stable across Node versions ✅ Works with CMake, Node-Gyp, or custom build systems ✅ Easier memory management than older approaches

Setup

mkdir node-cpp-addon
cd node-cpp-addon
npm init -y
npm install node-addon-api
npm install --save-dev node-gyp

Minimal Example | Add Two Numbers in C++

add.cpp

#include <napi.h>

Napi::Number Add(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    double a = info[0].As<Napi::Number>().DoubleValue();
    double b = info[1].As<Napi::Number>().DoubleValue();
    return Napi::Number::New(env, a + b);
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports.Set("add", Napi::Function::New(env, Add));
    return exports;
}
NODE_API_MODULE(addon, Init);

binding.gyp

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "add.cpp" ]
    }
  ]
}

Build & Run

npx node-gyp configure
npx node-gyp build

index.js

const addon = require('./build/Release/addon.node');
console.log(addon.add(10, 20));

Output:

30

Nice and simple, but not very practical yet.

A Real Use Case: Faster Image Blurring in C++

JavaScript can blur images, but it’s slow for large resolutions. Let’s write a high-performance blur filter in C++ and call it from Node.

Step 1: Add OpenCV or raw C++ logic

Here, we’ll write a simple box-blur over pixel data:

blur.cpp

#include <napi.h>
#include <vector>

Napi::Uint8Array Blur(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    auto input = info[0].As<Napi::Uint8Array>();
    int width = info[1].As<Napi::Number>();
    int height = info[2].As<Napi::Number>();
    std::vector<uint8_t> output(input.Length());
    for (int y = 1; y < height - 1; y++) {
        for (int x = 1; x < width - 1; x++) {
            int idx = (y * width + x) * 4;
            for (int c = 0; c < 3; c++) {
                int sum = 0;
                for (int dy = -1; dy <= 1; dy++) {
                    for (int dx = -1; dx <= 1; dx++) {
                        sum += input[( (y+dy) * width + (x+dx) ) * 4 + c];
                    }
                }
                output[idx + c] = sum / 9;
            }
            output[idx + 3] = 255; // Keep alpha
        }
    }
    auto result = Napi::Uint8Array::New(env, output.size());
    memcpy(result.Data(), output.data(), output.size());
    return result;
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports.Set("blur", Napi::Function::New(env, Blur));
    return exports;
}
NODE_API_MODULE(addon, Init);

Update binding.gyp:

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "blur.cpp" ]
    }
  ]
}

Rebuild:

npx node-gyp rebuild

Step 2: Use It in Node.js

const fs = require("fs");
const { createCanvas, loadImage } = require("canvas");
const addon = require("./build/Release/addon.node");

(async () => {
  const img = await loadImage("photo.jpg");
  const canvas = createCanvas(img.width, img.height);
  const ctx = canvas.getContext("2d");

  ctx.drawImage(img, 0, 0);
  let imageData = ctx.getImageData(0, 0, img.width, img.height);
  const blurred = addon.blur(imageData.data, img.width, img.height);
  imageData.data.set(blurred);
  ctx.putImageData(imageData, 0, 0);
  fs.writeFileSync("blurred.jpg", canvas.toBuffer("image/jpeg"));
})();

Performance Result

Javascript will take 260ms to perform the same logic (blurring 1920x1080 image) where c++ will only take 15ms

~17× faster with the same functionality.

🏁 Conclusion

Integrating C++ with Node.js is powerful when:

  • You need speed
  • You want to reuse existing C++ code
  • You process images, video, audio, data science, cryptography, ML

JavaScript stays productive. C++ handles the heavy lifting.

Find me on your favorite platform

  • Github — Follow me on GitHub for further useful code snippets and open source repos.
  • LinkedIn Profile — Connect with me on LinkedIn for further discussions and updates.
  • Twitter (X) — Connect with me on Twitter (X) for useless tech tweets.
  • Instagram — Connect with me on Instagram where i post stuff.

메타데이터
post_id
4f78f4cbb11a
slug
mixing-c-with-javascript-in-node-js-when-and-how-to-use-native-addons-4f78f4cbb11a
url
https://medium.com/@shaxadd/mixing-c-with-javascript-in-node-js-when-and-how-to-use-native-addons-4f78f4cbb11a
canonical_url
https://medium.com/@shaxadd/mixing-c-with-javascript-in-node-js-when-and-how-to-use-native-addons-4f78f4cbb11a
author_url
https://medium.com/@shaxadd
status
ok
fetched_at
2026-06-15 22:55:51