O contexto do Node-RED é o armazenamento chave-valor embutido que permite a um fluxo lembrar valores entre mensagens, como a última temperatura informada por um sensor ou a contagem de alarmes do dia. Este guia explica os três escopos de contexto, como fazer o contexto sobreviver a restarts, como usar vários stores ao mesmo tempo e um padrão limpo para guardar o último valor MQTT de cada dispositivo.
Por que os fluxos precisam de estado
As mensagens no Node-RED são independentes. Quando um node mqtt in emite uma leitura, o próximo node só conhece o que está dentro daquela mensagem. Muitas tarefas reais precisam de mais do que isso:
- Comparar um valor com o anterior para detectar uma mudança ou tendência.
- Responder a uma requisição HTTP com a leitura mais recente, mesmo que nenhuma mensagem MQTT esteja chegando naquele momento.
- Contar eventos por turno ou lembrar quando um alarme começou.
- Combinar valores de dois topics que chegam em momentos diferentes.
O próprio MQTT oferece uma forma de memória por meio das retained messages, em que o broker guarda a última mensagem de um topic e a entrega a novos assinantes. Isso é ótimo para estado compartilhado entre clientes, e você deve usar. O contexto é a ferramenta complementar para o estado que vive dentro do Node-RED. Se estiver em dúvida sobre de que lado fica cada responsabilidade, nosso guia sobre o que um broker MQTT faz traça essa linha.
Os três escopos de contexto do Node-RED
| Escopo | Visível para | Uso típico | Acesso em uma função |
|---|---|---|---|
| Node | Apenas o node que o definiu | Filtros de banda morta, contadores dentro de uma função | context.get() / context.set() |
| Flow | Todos os nodes da mesma aba (ou da mesma instância de subflow) | Últimos valores usados por vários nodes de uma aba | flow.get() / flow.set() |
| Global | Todos os nodes da instância do Node-RED | Configuração compartilhada, tabelas de consulta | global.get() / global.set() |
Escolha o escopo mais restrito que funcione. Um valor no contexto global pode ser alterado por qualquer node em qualquer aba, o que torna os bugs difíceis de rastrear. O contexto do node é privado, então nada mais pode quebrá-lo.
Você não precisa escrever código para usar contexto. O node Change consegue definir, ler, mover e apagar propriedades flow. e global., e os nodes Inject, Switch e Template conseguem lê-las. A aba Context Data na barra lateral do editor mostra os valores atuais de cada escopo e permite atualizar ou apagar entradas durante a depuração.
Os subflows têm um detalhe a mais: o contexto de flow dentro de um subflow pertence àquela instância. Um subflow pode acessar o contexto do fluxo pai com o prefixo $parent., como em flow.get("$parent.lastTemp").
Contexto em memória versus persistente
Por padrão, todo o contexto fica em memória. É rápido, mas desaparece quando o Node-RED reinicia, quando o contêiner é recriado ou quando o host é reinicializado. Para tudo o que você não consegue reconstruir com facilidade, ative o armazenamento em arquivo.
Abra o settings.js (em ~/.node-red/ numa instalação padrão, ou em /data/ na imagem Docker) e encontre a seção contextStorage:
// settings.js
module.exports = {
// ...
contextStorage: {
default: { module: "memory" },
file: { module: "localfilesystem" }
},
// ...
};
Reinicie o Node-RED. Agora você tem dois stores: default, que continua em memória, e file, que grava arquivos JSON na pasta context/ do seu diretório de usuário. Os nodes escolhem o store explicitamente:
flow.set("lastReading", msg.payload, "file"); // persistido
flow.set("scratch", 42); // memória (store padrão)
const last = flow.get("lastReading", "file");
No node Change e em outros editores, um pequeno seletor de store aparece ao lado dos campos flow. e global. assim que você tem mais de um store.
Se preferir tudo persistente, defina default: { module: "localfilesystem" }. Tenha em mente como o store em arquivo funciona: os valores ficam em cache na memória e são gravados em disco em intervalos, a cada 30 segundos por padrão, controlados pela opção flushInterval. Uma queda abrupta pode perder os últimos segundos de alterações. Isso não é problema para últimos valores e contadores, mas contexto não é banco de dados. Para dados históricos, grave em um banco de séries temporais como o InfluxDB, como mostrado no nosso guia de Node-RED com InfluxDB.
Observe também que apenas valores serializáveis em JSON persistem de forma confiável. Funções, timers e instâncias de classes não voltam intactos depois de um restart, então guarde objetos simples, números e strings.
Acesso síncrono e assíncrono
Com os stores memory e localfilesystem, get e set funcionam de forma síncrona, como mostrado acima. Alguns stores de terceiros, como módulos baseados em Redis, são assíncronos e exigem callbacks:
flow.get("count", "redis", (err, count) => {
if (err) { node.error(err, msg); return; }
count = (count || 0) + 1;
flow.set("count", count, "redis", (err) => {
if (err) { node.error(err, msg); return; }
msg.payload = count;
node.send(msg);
node.done();
});
});
Escrever código com callbacks desde o início custa pouco e permite trocar o store depois sem reescrever todas as funções. Saiba que um get seguido de um set não é atômico. Com taxas de mensagens muito altas em um store assíncrono, duas mensagens podem ler a mesma contagem antiga. Mantenha os contadores no contexto do node, onde só um node escreve, ou agrupe as atualizações.
Você também pode ler e gravar várias chaves de uma vez passando arrays: flow.get(["a", "b"]) retorna um array de valores.
Padrão: guardar o último valor MQTT de cada dispositivo
Uma tarefa comum do contexto no Node-RED é uma tabela ao vivo de "último valor conhecido": uma entrada por dispositivo, atualizada a cada mensagem e legível de qualquer ponto do fluxo. Imagine a caldeira de uma planta de alimentos no interior paulista. Publique alguns dados de teste no servidor MQTT público (gratuito) do ConnectMQ, que serve para testes e protótipos e não para dados de produção, substituindo c8d1 pela sua própria sequência aleatória:
mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-ctx-c8d1 \
-t "connectmq/demo/c8d1/boiler/tank1/telemetry" -m '{"level": 71.5, "temp": 63.2}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-ctx-c8d1 \
-t "connectmq/demo/c8d1/boiler/pump2/telemetry" -m '{"rpm": 1450, "temp": 41.0}'
Assine no Node-RED com um node mqtt in em connectmq/demo/c8d1/+/+/telemetry, com a saída configurada como JSON convertido, e ligue-o a esta função:
// Function "store latest"
const parts = msg.topic.split("/");
const deviceId = parts[3] + "/" + parts[4]; // ex.: "boiler/tank1"
const latest = flow.get("latest", "file") || {};
latest[deviceId] = {
values: msg.payload,
ts: Date.now()
};
flow.set("latest", latest, "file");
node.status({ text: Object.keys(latest).length + " devices" });
return null;
Agora qualquer node da aba pode ler a tabela. Um node http in em GET /latest, seguido desta função e de um node http response, entrega uma pequena API:
// Function "serve latest"
const latest = flow.get("latest", "file") || {};
const staleMs = 5 * 60 * 1000;
const now = Date.now();
msg.payload = Object.entries(latest).map(([id, v]) => ({
device: id,
values: v.values,
ageSeconds: Math.round((now - v.ts) / 1000),
stale: now - v.ts > staleMs
}));
return msg;
O indicador stale é o detalhe importante. Uma tabela de últimos valores que nunca expira mostra tranquilamente uma leitura de um dispositivo que parou ontem. Sempre guarde um timestamp junto com o valor.
Checklist de boas práticas de contexto no Node-RED
- Use o escopo mais restrito: node, depois flow, depois global.
- Habilite um store em arquivo e escolha-o explicitamente para valores que você não consegue reconstruir.
- Guarde timestamps junto com os valores para detectar dados desatualizados.
- Evite objetos enormes; entradas de contexto grandes deixam lentos cada flush e cada atualização da barra lateral.
- Use prefixos nas chaves globais conforme a finalidade, por exemplo
cfg_para configuração ecache_para dados de consulta. - Não guarde segredos no contexto. Credenciais pertencem aos nodes de configuração e às variáveis de ambiente.
- Use retained messages MQTT para estado de que outros clientes precisam e contexto para estado de que só o Node-RED precisa.
- Faça backup da pasta
context/junto com seus fluxos. Roda o Node-RED em contêineres? Nosso guia de Node-RED com Docker mostra como manter o/dataem um volume persistente.
A documentação oficial de contexto cobre por completo a API dos stores e as opções de configuração. Para o lado do código desses padrões, veja nosso guia do function node do Node-RED e, para a visão geral de como conectar fluxos a brokers, o tutorial de MQTT no Node-RED.
Combine o contexto do Node-RED com o ConnectMQ
O contexto guarda a memória do próprio Node-RED; o broker guarda a de todos os demais. O ConnectMQ é um broker MQTT gerenciado com retained messages, session expiry do MQTT 5 e TLS, para que dispositivos, dashboards e o Node-RED vejam os mesmos últimos valores conhecidos. O portal acrescenta um explorador de topics ao vivo e regras de alerta por limiar para verificações rápidas sem montar um fluxo. Comece no plano Serverless gratuito em app.connectmq.com, sem cartão de crédito, e conecte o Node-RED com o username, a senha e o client ID gerados.
Perguntas frequentes
Qual a diferença entre contexto flow e global no Node-RED?
O contexto flow é compartilhado apenas pelos nodes da mesma aba, enquanto o contexto global é compartilhado por todos os nodes da instância do Node-RED. Use o contexto flow, a menos que várias abas realmente precisem do mesmo valor.
Como faço o contexto do Node-RED sobreviver a um restart?
Adicione um store localfilesystem em contextStorage no settings.js, reinicie o Node-RED e grave nesse store, por exemplo flow.set("key", value, "file").
Onde o Node-RED guarda os arquivos de contexto persistente?
Em uma pasta context dentro do diretório de usuário do Node-RED, geralmente ~/.node-red/context ou /data/context no Docker, organizada por escopo.
Devo usar contexto ou retained messages MQTT para os últimos valores?
Use retained messages quando outros clientes MQTT precisarem do último valor e contexto quando só o Node-RED precisar dele, por exemplo para servir uma API ou comparar leituras. Muitos fluxos usam os dois.



