O Navigator no Node.js oferece uma implementação parcial da API conhecida dos navegadores. Ela expõe informações como quantidade de processadores lógicos, idioma preferido, plataforma, user agent e, em versões recentes, locks para coordenar acesso a recursos dentro do processo.
A presença dessa API facilita compartilhar bibliotecas entre navegador e servidor, reduzir condicionais específicas de ambiente e usar padrões dos Web Standards em aplicações Node.js. Ao mesmo tempo, os dados retornados não devem ser tratados como identidade confiável, autorização ou medição exata da capacidade real disponível em containers e ambientes limitados.
Neste guia, você aprenderá a usar navigator.hardwareConcurrency, language, languages, platform, userAgent e navigator.locks, além de aplicar feature detection, limitar concorrência, testar compatibilidade e evitar decisões inseguras.
Disponibilidade
A API Navigator é uma implementação parcial e pode continuar evoluindo. Consulte a documentação oficial do Navigator no Node.js e fixe a versão mínima do runtime.
if (typeof navigator === 'undefined') {
throw new Error('Navigator não está disponível');
}Também existe uma flag para desabilitar o global em versões compatíveis. Bibliotecas reutilizáveis devem verificar a disponibilidade em vez de assumir que o objeto existe.
hardwareConcurrency
console.log(navigator.hardwareConcurrency);A propriedade informa quantos processadores lógicos estão disponíveis para a instância do Node.js. Ela pode ajudar a definir um valor inicial para pools de Worker Threads ou tarefas paralelas.
const workers = Math.max(
1,
Math.min(navigator.hardwareConcurrency - 1, 8)
);Não crie automaticamente um worker para cada CPU sem medir. Tarefas podem disputar memória, banco, rede e event loop.
Containers e limites
Em containers, a quantidade reportada pode não representar exatamente o limite de CPU configurado pelo orquestrador. Sempre permita configuração explícita:
const configured = Number(process.env.WORKER_COUNT);
const workerCount = Number.isInteger(configured) && configured > 0
? configured
: Math.max(1, Math.min(navigator.hardwareConcurrency - 1, 4));Use métricas de CPU e latência para ajustar. Consulte Worker Threads no Node.js.
language
console.log(navigator.language); // exemplo: pt-BRO valor representa o idioma preferido do ambiente, normalmente derivado da configuração do sistema e da biblioteca ICU.
Ele pode servir como fallback em CLIs, mas não substitui a preferência explícita do usuário.
const language = process.env.APP_LANGUAGE
?? navigator.language
?? 'en-US';languages
console.log(navigator.languages);A lista pode conter apenas um valor em alguns ambientes. Não espere o mesmo comportamento detalhado de um navegador com várias preferências configuradas.
Para requisições HTTP, use o cabeçalho Accept-Language validado, não o idioma do processo.
Internacionalização
const formatter = new Intl.DateTimeFormat(language, {
dateStyle: 'long',
timeZone: 'America/Sao_Paulo'
});
console.log(formatter.format(new Date()));Use Intl para formatar datas, números e moedas. Não monte formatos manualmente.
Consulte Intl no Node.js.
platform
console.log(navigator.platform);A plataforma pode ajudar em mensagens, telemetria técnica e seleção de comportamento específico. Para decisões de sistema, process.platform continua sendo a API tradicional do Node.js.
const platform = navigator.platform || process.platform;Evite detectar plataforma para criar caminhos manualmente. Use node:path, que trata separadores corretamente.
userAgent
console.log(navigator.userAgent); // exemplo: Node.js/26O user agent identifica o runtime e sua versão principal. Ele não é um mecanismo de autenticação.
Não envie esse valor automaticamente para serviços externos se a política de privacidade não permitir. Ao fazer HTTP, defina um User-Agent específico da aplicação:
const response = await fetch(url, {
headers: {
'user-agent': 'orders-worker/2.4'
}
});Feature detection
Em bibliotecas multiplataforma, teste a propriedade necessária:
const concurrency = typeof navigator !== 'undefined' &&
Number.isInteger(navigator.hardwareConcurrency)
? navigator.hardwareConcurrency
: 1;Isso é melhor do que comparar versões por string.
Navigator em testes
Não altere o global diretamente quando ele for somente leitura. Encapsule o acesso:
export function getRuntimeInfo(nav = globalThis.navigator) {
return {
concurrency: nav?.hardwareConcurrency ?? 1,
language: nav?.language ?? 'en-US',
platform: nav?.platform ?? 'unknown'
};
}No teste:
import test from 'node:test';
import assert from 'node:assert/strict';
test('usa informações fornecidas', () => {
const info = getRuntimeInfo({
hardwareConcurrency: 4,
language: 'pt-BR',
platform: 'Linux'
});
assert.equal(info.concurrency, 4);
});A injeção evita testes dependentes da máquina do CI.
navigator.locks
Versões recentes podem oferecer navigator.locks, compatível com o modelo Web Locks. O recurso coordena acesso a recursos compartilhados entre threads do mesmo processo.
await navigator.locks.request('refresh-cache', async () => {
await refreshCache();
});O lock é liberado quando a callback termina, inclusive após erro.
Lock exclusivo
await navigator.locks.request(
'report-generation',
{ mode: 'exclusive' },
async () => {
await generateReport();
}
);Somente uma execução exclusiva mantém o recurso por vez.
Lock compartilhado
await navigator.locks.request(
'config-read',
{ mode: 'shared' },
async () => {
await readConfig();
}
);Vários leitores compartilhados podem operar juntos, enquanto um escritor exclusivo aguarda.
Escopo dos locks
Os locks coordenam recursos no mesmo processo e threads compatíveis. Eles não coordenam:
- pods diferentes;
- processos de cluster;
- servidores distintos;
- jobs externos;
- funções serverless separadas.
Para coordenação distribuída, use banco, Redis ou outro mecanismo apropriado.
Veja Locks Distribuídos com Redis.
Timeout de lock
Uma operação pode aguardar indefinidamente se não houver política. Combine com AbortSignal quando suportado pela opção usada:
const signal = AbortSignal.timeout(5_000);
await navigator.locks.request(
'expensive-task',
{ signal },
async () => runTask()
);Trate timeout separadamente e registre a contenção.
Evite deadlocks
Se a aplicação precisa de mais de um lock, mantenha uma ordem global:
// Sempre obtenha account antes de ledger
await navigator.locks.request('account', async () => {
await navigator.locks.request('ledger', async () => {
await updateBoth();
});
});Melhor ainda: redesenhe para um lock único ou transação quando possível.
Não faça I/O lento sem limite
Uma callback que mantém lock durante chamada externa pode bloquear todo o processo.
await navigator.locks.request('cache', async () => {
const result = await fetchWithTimeout(endpoint);
await store(result);
});Quando possível, faça o trabalho lento fora do lock e mantenha apenas a atualização crítica dentro dele.
Pool de workers
Use hardwareConcurrency como ponto inicial, não verdade absoluta:
function choosePoolSize({
logicalProcessors = navigator.hardwareConcurrency,
max = 6
} = {}) {
return Math.max(1, Math.min(logicalProcessors - 1, max));
}Meça fila, tempo de espera e CPU. Um pool menor pode entregar melhor latência.
CLI adaptativa
Uma CLI pode usar idioma e plataforma para defaults:
const defaults = {
language: navigator.language,
platform: navigator.platform,
parallelism: Math.min(navigator.hardwareConcurrency, 4)
};Mostre ao usuário as escolhas e permita sobrescrever.
Logs e diagnóstico
logger.info({
runtime: navigator.userAgent,
platform: navigator.platform,
concurrency: navigator.hardwareConcurrency
}, 'runtime_info');Não use os valores como labels de alta cardinalidade sem normalização.
Privacidade
Embora os dados pareçam técnicos, combinar plataforma, idioma e versão pode aumentar fingerprinting. Envie somente o necessário e documente a telemetria.
Compatibilidade entre navegador e Node.js
Uma biblioteca compartilhada pode usar Navigator para defaults, mas não espere todas as propriedades do browser.
export function preferredLanguage() {
return globalThis.navigator?.language ?? 'en-US';
}Faça feature detection para cada campo e mantenha fallback.
Diferença para process
navigator.platform: interface compatível com Web Standards;process.platform: identificador específico do Node.js;navigator.hardwareConcurrency: quantidade lógica disponível;os.cpus(): detalhes de CPUs;navigator.language: preferência de idioma;process.env: configuração explícita.
Escolha a API conforme a intenção.
Erros comuns
- usar hardwareConcurrency como tamanho obrigatório;
- ignorar limites de container;
- usar language como preferência do usuário HTTP;
- tratar userAgent como autenticação;
- supor API completa do navegador;
- usar locks para coordenação distribuída;
- manter lock durante operação sem timeout;
- testar diretamente contra a máquina do CI;
- não oferecer configuração explícita.
Checklist
- fixe versão mínima;
- use feature detection;
- permita overrides;
- limite paralelismo;
- meça CPU e fila;
- trate idioma como fallback;
- não confie em userAgent;
- entenda o escopo dos locks;
- use timeout;
- injete Navigator nos testes.
Conclusão
O Navigator no Node.js aproxima o runtime dos Web Standards e oferece informações úteis sobre concorrência, idioma, plataforma e versão. A API pode reduzir diferenças entre código de navegador e servidor.
Use esses valores como defaults e sinais de diagnóstico, nunca como identidade ou autorização. Para locks, respeite o escopo do processo e mantenha regiões críticas curtas. Com feature detection e configuração explícita, Navigator se torna uma camada útil sem esconder as limitações do ambiente real.
Como referência complementar, consulte a especificação do objeto Navigator.


