Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Node-API no Node.js: Guia Prático

Atualizado em: 16 de agosto de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

A Node-API no Node.js é uma interface C estável para criar addons nativos que podem continuar compatíveis entre diferentes versões do runtime. Em vez de depender diretamente das APIs internas do V8, um addon usa funções e tipos definidos pelo Node.js, reduzindo a necessidade de recompilar a cada atualização.

Node-API é útil quando JavaScript sozinho não atende requisitos de desempenho, integração com bibliotecas C ou C++, acesso a hardware, codecs, bancos embarcados ou APIs de sistema. O ganho vem acompanhado de complexidade: gerenciamento de memória, erros, threads, builds por plataforma e riscos de segurança.

Neste guia, você aprenderá a estrutura de um addon, valores napi, funções exportadas, erros, referências, buffers, callbacks assíncronos, thread-safe functions, object wrap, versionamento, build, distribuição e testes.

O que é Node-API?

Node-API, anteriormente chamada N-API, fornece uma ABI para addons nativos. A documentação oficial de Node-API descreve funções, versões e padrões. O projeto node-addon-api no GitHub oferece wrappers C++ sobre a API C.

Para entender o sistema de módulos, consulte Module API no Node.js. Para trabalho em threads, veja Worker Threads no Node.js. O artigo sobre Buffer no Node.js ajuda na troca de dados binários.

Quando usar Node-API?

  • integrar biblioteca nativa existente;
  • acessar dispositivo ou driver;
  • executar algoritmo intensivo otimizado;
  • implementar codec;
  • criar bridge para SDK do sistema;
  • reutilizar código C ou C++.

Antes de criar um addon, avalie WebAssembly, Worker Threads ou processo separado. Código nativo pode derrubar todo o processo se houver acesso inválido à memória.

Estrutura mínima em C

#include <node_api.h>

napi_value Add(
  napi_env env,
  napi_callback_info info
) {
  napi_value result;
  napi_create_int32(env, 42, &result);
  return result;
}

NAPI_MODULE_INIT() {
  napi_value fn;
  napi_create_function(
    env,
    "add",
    NAPI_AUTO_LENGTH,
    Add,
    NULL,
    &fn
  );
  napi_set_named_property(env, exports, "add", fn);
  return exports;
}

O módulo exporta uma função JavaScript que retorna 42.

napi_env

napi_env representa o ambiente da chamada. Ele deve ser usado apenas no contexto e thread permitidos. Não armazene para uso arbitrário em outra thread.

napi_value

Valores JavaScript são representados por napi_value. Eles não são ponteiros comuns e devem ser manipulados pelas funções da API.

Recebendo argumentos

size_t argc = 2;
napi_value argv[2];
napi_value this_arg;

napi_get_cb_info(
  env,
  info,
  &argc,
  argv,
  &this_arg,
  NULL
);

Valide a quantidade e os tipos antes de converter.

Verificando tipos

napi_valuetype type;
napi_typeof(env, argv[0], &type);

if (type != napi_number) {
  napi_throw_type_error(
    env,
    NULL,
    "O primeiro argumento deve ser número"
  );
  return NULL;
}

Convertendo números

double value;
napi_get_value_double(env, argv[0], &value);

Considere limites de precisão, NaN e Infinity.

Strings

Primeiro consulte o tamanho, depois aloque:

size_t length;
napi_get_value_string_utf8(
  env,
  argv[0],
  NULL,
  0,
  &length
);

char* text = malloc(length + 1);

napi_get_value_string_utf8(
  env,
  argv[0],
  text,
  length + 1,
  &length
);

Libere a memória em todos os caminhos de erro. Defina limite antes de alocar entrada enorme.

Macros de verificação

#define NAPI_CALL(env, call) do { \
  napi_status status = (call); \
  if (status != napi_ok) { \
    const napi_extended_error_info* info; \
    napi_get_last_error_info((env), &info); \
    napi_throw_error((env), NULL, info->error_message); \
    return NULL; \
  } \
} while (0)

Centralizar checagem reduz caminhos esquecidos, mas não exponha mensagens internas sensíveis.

Objetos

napi_value object;
napi_create_object(env, &object);

napi_value name;
napi_create_string_utf8(
  env,
  "Node-API",
  NAPI_AUTO_LENGTH,
  &name
);

napi_set_named_property(
  env,
  object,
  "name",
  name
);

Arrays

napi_value array;
napi_create_array_with_length(env, 3, &array);

Use napi_set_element() para preencher.

Buffers

void* data;
napi_value buffer;

napi_create_buffer(
  env,
  1024,
  &data,
  &buffer
);

O Node.js gerencia a memória desse Buffer. Não use o ponteiro depois que o valor puder ser coletado.

External Buffer

É possível criar Buffer sobre memória externa com callback finalizador. Isso exige ownership claro para evitar double free ou use-after-free.

ArrayBuffer e TypedArray

Node-API fornece funções para consultar ArrayBuffer e TypedArray. Valide offset, tamanho e tipo antes de acessar bytes.

Referências

napi_ref reference;
napi_create_reference(
  env,
  value,
  1,
  &reference
);

Referências mantêm acesso a valores além da chamada atual. Elas precisam ser removidas com napi_delete_reference().

Referência fraca

Uma contagem inicial zero pode representar referência que não impede garbage collection. Teste se o valor ainda existe antes de usar.

Handles e escopos

Chamadas que criam muitos valores podem usar handle scopes:

napi_handle_scope scope;
napi_open_handle_scope(env, &scope);

// criar valores

napi_close_handle_scope(env, scope);

Isso permite liberar handles temporários antes do final de uma operação longa.

Escopo escapável

Quando um valor precisa sair do escopo, use escapable handle scope conforme a documentação.

Erros JavaScript

napi_throw_error(
  env,
  "ERR_NATIVE_OPERATION",
  "Falha na operação nativa"
);

Depois de lançar, retorne e interrompa o caminho normal.

Exceção pendente

Use funções para verificar se existe exceção pendente. Não continue criando resultados como se a operação tivesse sucesso.

Promises

napi_deferred deferred;
napi_value promise;

napi_create_promise(
  env,
  &deferred,
  &promise
);

Depois, resolva ou rejeite na thread JavaScript apropriada.

Trabalho assíncrono

napi_create_async_work() permite executar trabalho fora da thread principal e concluir no event loop.

napi_async_work work;

napi_create_async_work(
  env,
  NULL,
  resource_name,
  Execute,
  Complete,
  context,
  &work
);

napi_queue_async_work(env, work);

Função Execute

Execute roda fora da thread JavaScript. Não chame APIs napi que exigem env nessa fase. Trabalhe apenas com dados nativos.

Função Complete

Complete roda na thread apropriada e pode criar valores, resolver Promise e liberar o work.

Cancelamento

napi_cancel_async_work() solicita cancelamento de trabalho ainda não iniciado. Código em execução precisa de mecanismo cooperativo próprio.

Thread-safe function

Uma thread nativa externa não pode chamar JavaScript diretamente. Use napi_threadsafe_function para enfileirar dados de forma segura.

Backpressure em thread-safe function

Defina tamanho máximo da fila e comportamento bloqueante ou não bloqueante. Uma fonte nativa rápida pode consumir toda a memória.

Finalização da thread-safe function

Libere cada aquisição e finalize quando não houver produtores. Erros nessa contagem podem impedir shutdown ou causar acesso inválido.

AsyncResource e contexto

Operações nativas assíncronas devem manter contexto para observabilidade. Consulte AsyncResource no Node.js.

Object Wrap

napi_wrap() associa um ponteiro nativo a um objeto JavaScript. Um finalizador libera o recurso quando o objeto é coletado.

Ownership

Defina claramente quem possui:

  • memória nativa;
  • handle do sistema;
  • referência JavaScript;
  • fila assíncrona;
  • callback finalizador.

Finalizadores

Finalizadores não devem executar trabalho longo ou depender de ordem previsível de garbage collection. Para recursos críticos, exponha método close() explícito.

Versão da Node-API

O runtime expõe versões da API. Compile para a menor versão que contém os recursos necessários para ampliar compatibilidade.

Features condicionais

Quando uma função depende de versão recente, detecte em build ou runtime e forneça fallback claro.

node-addon-api

O wrapper C++ oferece classes como Napi::Env, Napi::Value e Napi::ObjectWrap. Ele melhora ergonomia, mas continua exigindo tratamento de memória e threads.

Build com node-gyp

Um arquivo binding.gyp descreve fontes e flags:

{
  "targets": [
    {
      "target_name": "addon",
      "sources": ["src/addon.c"]
    }
  ]
}

Carregando o addon

const addon = require('./build/Release/addon.node');

Para pacotes distribuídos, use resolução compatível com a plataforma e arquitetura.

Prebuilds

Oferecer binários pré-compilados evita exigir compilador no computador do usuário. Crie matriz para sistemas e arquiteturas suportados.

Fallback de compilação

Quando não houver prebuild, o pacote pode compilar localmente. Documente requisitos de Python, compilador e headers.

Containers e libc

Linux glibc e musl podem exigir artefatos diferentes. Teste Alpine e distribuições baseadas em glibc separadamente.

Assinatura e cadeia de suprimentos

Binários nativos possuem alto privilégio dentro do processo. Publique checksums, proteja CI e limite quem pode gerar releases.

Segurança de memória

Erros em C ou C++ podem causar:

  • segmentation fault;
  • corrupção de heap;
  • leitura fora de limite;
  • use-after-free;
  • double free;
  • execução de código.

Use sanitizers em testes e fuzzing em parsers.

Validação de entrada

Valide tamanhos antes de converter para tipos menores. Não confie em comprimentos recebidos do JavaScript.

Thread safety

Nem toda biblioteca nativa é thread-safe. Proteja estado ou confine cada instância a uma thread.

Event loop

Não execute trabalho pesado diretamente no callback JavaScript. Use async work ou Worker Thread para evitar bloquear a aplicação.

Testes

Cubra:

  • tipos válidos e inválidos;
  • strings vazias e enormes;
  • buffers pequenos e grandes;
  • erros nativos;
  • Promise resolvida e rejeitada;
  • cancelamento;
  • shutdown;
  • garbage collection;
  • múltiplas threads;
  • plataformas suportadas.

Sanitizers

Use AddressSanitizer, UndefinedBehaviorSanitizer e ferramentas da plataforma em builds de teste.

Erros comuns

  • Ignorar napi_status: o código continua após falha.
  • Usar env em thread externa: o processo pode falhar.
  • Esquecer referência: valores são coletados ou vazam.
  • Bloquear o event loop: latência aumenta.
  • Sem limite de fila: memória cresce.
  • Distribuir um único binário: plataformas incompatíveis falham.
  • Confiar apenas em GC: recursos críticos ficam abertos.

Boas práticas

  • Prefira Node-API a APIs internas do V8.
  • Cheque todo napi_status.
  • Valide entradas.
  • Defina ownership.
  • Use async work.
  • Use thread-safe functions.
  • Limite filas.
  • Ofereça close explícito.
  • Teste com sanitizers.
  • Publique prebuilds seguros.

Conclusão

A Node-API no Node.js oferece uma ABI estável para integrar código nativo sem depender diretamente das mudanças internas do V8.

Ela permite addons potentes, mas transfere ao desenvolvedor responsabilidades de memória, threads, builds e segurança. Com validação rigorosa, async work, ownership explícito, testes com sanitizers e artefatos por plataforma, Node-API pode conectar o ecossistema JavaScript a bibliotecas nativas sem sacrificar compatibilidade operacional.

Os 10 Melhores Cursos de Programação de 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita