[{"data":1,"prerenderedAt":403},["ShallowReactive",2],{"agmd-node-red-handling-data":3,"application-guide-nav":295},{"id":4,"title":5,"blurb":6,"body":7,"description":20,"extension":285,"guide":286,"meta":287,"navOrder":288,"navTitle":5,"navigation":289,"parent":290,"path":291,"seo":292,"slug":13,"stem":293,"__hash__":294},"applicationGuideDoc\u002Fapplication-guide\u002Fnode-red\u002Fhandling-data.md","Handling data","Classify each signal by shape, purpose and direction, then pick the methods it needs — separate the paths, pace the flow, hold state in context, and manage config. The methods you select to move a flow's data.",{"type":8,"value":9,"toc":281},"minimark",[10,14,21,28],[11,12,5],"h1",{"id":13},"handling-data",[15,16,17],"p",{},[18,19,20],"strong",{},"Handling data — classify what you've got, then pick your methods",[15,22,23,24,27],{},"A flow's data isn't one thing. First ",[18,25,26],{},"classify"," each signal — by shape, purpose, and direction — then select the handling methods each kind needs. Building a flow you'll usually reach for more than one: separate the paths, pace the flow, hold state in context, manage config. Start in the first tab; the rest are the methods you choose from.",[29,30,31,123,157,191,241],"guide-tabs",{},[32,33,35,46,49,54,78,83,89,109,114,117],"guide-tab",{"label":34},"Classify the data",[15,36,37,40,41,45],{},[18,38,39],{},"Know what kind of data you're handling"," — before you pick any method, name each signal by its shape, its purpose, and its direction. What a signal ",[42,43,44],"em",{},"is"," decides how you move it, how fast, and where it's stored. Mixing kinds — and polling everything at the fastest rate — is what creates load a controller can't sustain.",[15,47,48],{},"Every point you touch is some combination of the three:",[15,50,51],{},[18,52,53],{},"By shape — is it an event or a stream?",[55,56,57,68],"ul",{},[58,59,60,63,64,67],"li",{},[18,61,62],{},"Event"," — something happened at a moment: a button press, a state change, a fault, a batch complete. Discrete and irregular, and each one matters on its own. You handle it ",[42,65,66],{},"when it fires"," — you don't poll for it.",[58,69,70,73,74,77],{},[18,71,72],{},"Stream"," — a continuous series of readings sampled on a clock: temperature, flow, level, vibration. Regular and high-volume, where the latest value usually matters more than any single earlier one. You read it ",[42,75,76],{},"at a cadence"," and often only keep the trend.",[15,79,80],{},[18,81,82],{},"By purpose — what is the value for?",[84,85],"flow-diagram",{":edges":86,":nodes":87,"align":88},"[{\"from\":\"src\",\"to\":\"telemetry\"},{\"from\":\"src\",\"to\":\"control\"},{\"from\":\"src\",\"to\":\"config\"}]","[{\"id\":\"src\",\"label\":\"a signal\",\"sub\":\"event or stream\",\"accent\":\"slate\",\"col\":1,\"row\":2},{\"id\":\"telemetry\",\"label\":\"Telemetry\",\"sub\":\"observe & trend · latency-tolerant\",\"accent\":\"green\",\"col\":2,\"row\":1},{\"id\":\"control\",\"label\":\"Control\",\"sub\":\"drives a decision · time-critical\",\"accent\":\"red\",\"col\":2,\"row\":2},{\"id\":\"config\",\"label\":\"Config\",\"sub\":\"shapes the app · written rarely\",\"accent\":\"slate\",\"col\":2,\"row\":3}]","left",[55,90,91,97,103],{},[58,92,93,96],{},[18,94,95],{},"Telemetry"," — readings you observe and trend. Continuous and latency-tolerant: a second late only moves a timestamp.",[58,98,99,102],{},[18,100,101],{},"Control"," — a value that drives a decision or an actuator. Small and time-critical: a second late changes an outcome.",[58,104,105,108],{},[18,106,107],{},"Config"," — a setting that shapes how the app runs. Written rarely, read often.",[15,110,111],{},[18,112,113],{},"By direction — read or write?",[15,115,116],{},"Reading a value out of a device and writing one back into it are not the same cost or risk. Writes touch the process; treat them with more care and a tighter path than the reads you take for observation.",[15,118,119,122],{},[18,120,121],{},"Put it together"," — for each point, ask: event or stream? Does a delay change a decision or only a timestamp? Read or write? Those three answers set its rate, its path, and its store — and point you at the methods in the next tabs. The common mistake is treating every point as one population and polling all of it at the fastest rate; usually only a handful genuinely need the fast path, and the rest just starve the ones that do.",[32,124,126,132,138,142,145,151],{"label":125},"Separate the paths",[15,127,128,131],{},[18,129,130],{},"Telemetry one way, control another"," — give each kind its own route so the fast path never inherits the slow one's load.",[15,133,134,137],{},[42,135,136],{},"Select when — a flow carries both telemetry and control (from Classify)."," This split is the foundational method; the pacing and storage choices all follow from it.",[84,139],{":edges":140,":nodes":141,"align":88},"[{\"from\":\"plc\",\"to\":\"nodered\",\"label\":\"reads\"},{\"from\":\"nodered\",\"to\":\"broker\",\"label\":\"live\"},{\"from\":\"nodered\",\"to\":\"ctrl\",\"label\":\"control write\",\"accent\":\"red\"},{\"from\":\"nodered\",\"to\":\"sqldb\",\"label\":\"history, batched\"}]","[{\"id\":\"plc\",\"label\":\"PLC\",\"sub\":\"reads · writes\",\"col\":1,\"row\":2},{\"id\":\"nodered\",\"label\":\"Node-RED\",\"sub\":\"splits by kind\",\"accent\":\"slate\",\"col\":2,\"row\":2},{\"id\":\"broker\",\"label\":\"Broker\",\"sub\":\"live telemetry · minimal set\",\"accent\":\"teal\",\"col\":3,\"row\":1},{\"id\":\"ctrl\",\"label\":\"actuator \u002F setpoint\",\"sub\":\"control · lean, dedicated\",\"accent\":\"red\",\"col\":3,\"row\":2},{\"id\":\"sqldb\",\"label\":\"SQL database\",\"sub\":\"history telemetry · batched\",\"accent\":\"green\",\"col\":3,\"row\":3}]",[15,143,144],{},"Telemetry and control have different timing needs. Share one route and one protocol, and the fast, time-critical path inherits the load of the slow, high-volume one — a burst of telemetry can delay a control decision.",[15,146,147,150],{},[18,148,149],{},"How"," — buffer telemetry in the source and pull it at its real cadence, timestamped at acquisition, then batch it into history. Keep the control path to the minimum tag set on a dedicated, faster route. Reads you take for observation and writes that touch the process never share a lane.",[15,152,153,156],{},[18,154,155],{},"The payoff"," — the fast path stays lean no matter how much telemetry flows, and each kind can be paced and stored on its own terms.",[32,158,160,166,172,177,180,185],{"label":159},"Batch \u002F rate-limit",[15,161,162,165],{},[18,163,164],{},"Pace a fast source into a slow sink"," — add the brake that a fast-in \u002F slow-out path doesn't have on its own.",[15,167,168,171],{},[42,169,170],{},"Select when — a fast or bursty source (a stream, or high-rate events) feeds a slower sink."," This is the #1 event-driven failure, so reach for it whenever input can outrun output.",[84,173],{":edges":174,":nodes":175,":legend":176},"[{\"from\":\"mqtt\",\"to\":\"pace\",\"label\":\"many msg\u002Fs\",\"accent\":\"indigo\",\"dashed\":true},{\"from\":\"pace\",\"to\":\"db\",\"label\":\"steady rate\"}]","[{\"id\":\"mqtt\",\"label\":\"MQTT in\",\"sub\":\"fast · bursty\",\"accent\":\"teal\",\"col\":1},{\"id\":\"pace\",\"label\":\"rate limit \u002F batch\",\"sub\":\"delay · queue · drop\",\"col\":2},{\"id\":\"db\",\"label\":\"DB write\",\"sub\":\"slow · the bottleneck\",\"accent\":\"green\",\"col\":3}]","[{\"line\":\"indigo\",\"dashed\":true,\"label\":\"fast in\"},{\"line\":\"neutral\",\"label\":\"paced out\"}]",[15,178,179],{},"A fast source (an MQTT topic, a tight poll) feeding a slow sink (a DB write, a remote API) has no natural brake. Messages pile up in memory faster than they drain, and the runtime eventually runs out of heap and dies.",[15,181,182,184],{},[18,183,149],{}," — a delay node in rate-limit mode; batching (join into chunks), which also cuts per-write overhead; or dropping stale readings when only the latest matters. Watch heap and the node's queue — if it only grows, you have backpressure, not a spike.",[15,186,187,190],{},[18,188,189],{},"The tell"," — a backend holding a live connection (an MQTT subscription) can't be pooled away; pace at the source or offload the heavy work.",[32,192,194,200,206,211,214,235],{"label":193},"Hold state in context",[15,195,196,199],{},[18,197,198],{},"One place for state"," — keep a logical object in context instead of threading it through wires.",[15,201,202,205],{},[42,203,204],{},"Select when — you're passing the same object through many nodes just to move it, or state must survive a restart."," Messages are verbs; context is nouns.",[84,207],{":edges":208,":nodes":209,":legend":210},"[\"event>node\",{\"from\":\"node\",\"to\":\"store\",\"label\":\"write\"},{\"from\":\"store\",\"to\":\"reader\",\"label\":\"read the one key it needs\",\"dashed\":true}]","[{\"id\":\"event\",\"label\":\"event\",\"sub\":\"a reading arrived\",\"col\":1,\"row\":1},{\"id\":\"node\",\"label\":\"node\",\"sub\":\"recompute\",\"col\":2,\"row\":1,\"accent\":\"indigo\"},{\"id\":\"store\",\"label\":\"context store\",\"sub\":\"assets.\u003Cid>, oee.line1\",\"col\":3,\"row\":1,\"accent\":\"green\"},{\"id\":\"reader\",\"label\":\"another node\",\"sub\":\"reads one key\",\"col\":2,\"row\":2}]","[{\"line\":\"neutral\",\"label\":\"write \u002F flow\"},{\"line\":\"neutral\",\"dashed\":true,\"label\":\"read\"}]",[15,212,213],{},"Context is shared memory with a defined scope. It holds a logical object in one place instead of threading it through fifteen nodes just to carry it — wire gymnastics to avoid storing a value is the real anti-pattern.",[15,215,216,218,219,222,223,226,227,230,231,234],{},[18,217,149],{}," — store the object once under a namespaced key at the narrowest scope that works. ",[18,220,221],{},"Node"," scope is private to that one node, so anything ",[42,224,225],{},"shared"," between nodes starts at ",[18,228,229],{},"flow"," scope (then ",[18,232,233],{},"global"," only if it must cross tabs). Each node reads the one key it needs, and a persistent store holds anything that must survive a restart.",[15,236,237,240],{},[18,238,239],{},"Watch out"," — one writer per key, serialize concurrent updates, and keep enough on the wire to stay debuggable.",[32,242,243,249,255,260,270,275],{"label":107},[15,244,245,248],{},[18,246,247],{},"Static in env vars, runtime in persisted context"," — decide which kind each setting is, then store it accordingly.",[15,250,251,254],{},[42,252,253],{},"Select when — the flow has settings."," The question for each one: does it change per environment at deploy, or while running, by a user?",[84,256],{":edges":257,":nodes":258,":groups":259},"[{\"from\":\"ui\",\"to\":\"store\",\"label\":\"intent\"},\"store>flowrun\"]","[{\"id\":\"broker\",\"label\":\"BROKER_HOST\",\"sub\":\"baked, read-only — edit env + redeploy\",\"col\":1,\"row\":1,\"accent\":\"slate\"},{\"id\":\"ui\",\"label\":\"UI edits\",\"sub\":\"a form or button\",\"col\":2,\"row\":1,\"accent\":\"indigo\"},{\"id\":\"store\",\"label\":\"context store\",\"sub\":\"live config\",\"col\":3,\"row\":1,\"accent\":\"green\"},{\"id\":\"flowrun\",\"label\":\"flow at run\",\"sub\":\"reads current\",\"col\":4,\"row\":1}]","[{\"label\":\"Env var — set at deploy\",\"nodes\":[\"broker\"]},{\"label\":\"Persisted context — changed by a user\",\"accent\":\"green\",\"nodes\":[\"ui\",\"store\",\"flowrun\"]}]",[15,261,262,265,266,269],{},[18,263,264],{},"Static config"," changes per environment and is set at deploy — broker host, DB connection. It's resolved at deploy time and read-only to the running flow. ",[18,267,268],{},"Runtime config"," changes while running, by a user, with no redeploy.",[15,271,272,274],{},[18,273,149],{}," — keep static config in env vars or a config node; put user-editable config in persisted context (or a config file), edited through the UI via an intent message and read by the flow at execution time.",[15,276,277,280],{},[18,278,279],{},"The rule"," — if a value would ever be changed through a button or form, it is not an env var.",{"title":282,"searchDepth":283,"depth":283,"links":284},"",4,[],"md","node-red",{},3.2,true,"patterns","\u002Fapplication-guide\u002Fnode-red\u002Fhandling-data",{"title":5,"description":20},"application-guide\u002Fnode-red\u002Fhandling-data","w93FmlxICN8_TOPe0zl1bZ0k8sDYQ8ExGdsaVXm3uzg",[296,304,307,313,316,322,326,332,337,342,344,350,355,360,366,372,378,383,388,393,397],{"guide":297,"slug":298,"title":299,"navOrder":300,"parent":301,"blurb":302,"path":303},"flowfuse","overview","Overview",1,null,"The map of the FlowFuse guide — apps, architectures, and a worked example.","\u002Fapplication-guide\u002Fflowfuse\u002Foverview\u002F",{"guide":286,"slug":298,"title":299,"navOrder":300,"parent":301,"blurb":305,"path":306},"The map of the Node-RED guide — the pattern families that turn an app into a clean flow.","\u002Fapplication-guide\u002Fnode-red\u002Foverview\u002F",{"guide":297,"slug":308,"title":309,"navOrder":310,"parent":301,"blurb":311,"path":312},"foundations","Foundations",2,"The foundation to build on: what FlowFuse is, its core pieces, and how code is shared across teams.","\u002Fapplication-guide\u002Fflowfuse\u002Ffoundations\u002F",{"guide":286,"slug":308,"title":309,"navOrder":310,"parent":301,"blurb":314,"path":315},"The handful of concepts you need to build with Node-RED, and how they fit together.","\u002Fapplication-guide\u002Fnode-red\u002Ffoundations\u002F",{"guide":297,"slug":317,"title":318,"navOrder":319,"parent":301,"blurb":320,"path":321},"app-delivery-methods","App delivery methods",3,"Two different units of code, delivered two ways. Ship the whole app — a complete, versioned project promoted through environments — or publish one reusable piece — a package the whole team installs and upgrades in one place. Pick by what you're shipping: the app, or a part of it.","\u002Fapplication-guide\u002Fflowfuse\u002Fapp-delivery-methods\u002F",{"guide":286,"slug":290,"title":323,"navOrder":319,"parent":301,"blurb":324,"path":325},"Patterns","The moves that turn an architecture into a clean, reusable flow — find the seams and reuse well, then handle data on the right paths.","\u002Fapplication-guide\u002Fnode-red\u002Fpatterns\u002F",{"guide":297,"slug":327,"title":328,"navOrder":329,"parent":317,"blurb":330,"path":331},"hardware-apps","Hardware apps",3.1,"The three shapes a FlowFuse app takes when it runs on a device. Pick by how much varies per site: nothing (Packaged App), a few settings (Configurable App), or you assemble it yourself (Edge Building Block).","\u002Fapplication-guide\u002Fflowfuse\u002Fhardware-apps\u002F",{"guide":286,"slug":333,"title":334,"navOrder":329,"parent":290,"blurb":335,"path":336},"design-patterns","Design patterns","The structural choices you select for a flow: find the seams it breaks into, then reuse each piece at the lightest level that solves it — link in\u002Fout, link call, subflow, or packaged node.","\u002Fapplication-guide\u002Fnode-red\u002Fdesign-patterns\u002F",{"guide":297,"slug":338,"title":339,"navOrder":288,"parent":317,"blurb":340,"path":341},"software-apps","Software apps","The three shapes a FlowFuse app takes when it runs on the platform. Pick by what it needs: a headless job (Packaged App), a user-facing app driven by data (Data-Driven App), or a reusable piece other apps embed (Shared Building Block).","\u002Fapplication-guide\u002Fflowfuse\u002Fsoftware-apps\u002F",{"guide":286,"slug":13,"title":5,"navOrder":288,"parent":290,"blurb":6,"path":343},"\u002Fapplication-guide\u002Fnode-red\u002Fhandling-data\u002F",{"guide":286,"slug":345,"title":346,"navOrder":347,"parent":290,"blurb":348,"path":349},"good-form","Good form",3.3,"A clean flow isn't luck — it's a handful of habits. Wire for reading, lay it out on a grid, decouple UI from logic, catch errors where you can see them, and keep data on a stable contract. Follow these and a flow stays readable, reusable, and out of spaghetti.","\u002Fapplication-guide\u002Fnode-red\u002Fgood-form\u002F",{"guide":297,"slug":351,"title":352,"navOrder":283,"parent":301,"blurb":353,"path":354},"data-plane","Data plane","Before you pick where things run, decide how data is handled. Two stores come built into every FlowFuse server install — the Team Broker and relational Tables — exposed to every instance with nothing extra to stand up. Everything else you bring your own: run it (a time-series DB, an existing database, a model) and expose it to the fleet over Project Link, no inbound ports. This is the data plane the architectures on the next pages all sit on.","\u002Fapplication-guide\u002Fflowfuse\u002Fdata-plane\u002F",{"guide":286,"slug":356,"title":357,"navOrder":283,"parent":301,"blurb":358,"path":359},"worked-examples","Worked examples","Turn an app concept into a Node-RED flow — or a few — leaning on the design patterns and data handling. The method, then the OEE apps end to end.","\u002Fapplication-guide\u002Fnode-red\u002Fworked-examples\u002F",{"guide":286,"slug":361,"title":362,"navOrder":363,"parent":356,"blurb":364,"path":365},"oee-edge-aggregator","OEE - Edge Aggregator",4.1,"The edge app from the OEE use case as a Node-RED flow — a straight-line flow packaged as a subflow and configured per line (its PLC tags, via a config UI and a get-config node), with the data treated as a stream and its counts held in context.","\u002Fapplication-guide\u002Fnode-red\u002Foee-edge-aggregator\u002F",{"guide":286,"slug":367,"title":368,"navOrder":369,"parent":356,"blurb":370,"path":371},"oee-central-dashboard","OEE - Central Dashboard",4.2,"The cloud app from the OEE use case as a Node-RED flow — one link out fanning to two link ins on separate tabs (dashboard and batched history), so the live and history paths stay separate and easy to read.","\u002Fapplication-guide\u002Fnode-red\u002Foee-central-dashboard\u002F",{"guide":297,"slug":373,"title":374,"navOrder":375,"parent":301,"blurb":376,"path":377},"architectures","Architectures",5,"Every FlowFuse deployment is the same building blocks arranged for where it runs — pick the world you're designing for.","\u002Fapplication-guide\u002Fflowfuse\u002Farchitectures\u002F",{"guide":297,"slug":379,"title":380,"navOrder":381,"parent":373,"blurb":301,"path":382},"it-architectures","IT architectures",5.1,"\u002Fapplication-guide\u002Fflowfuse\u002Fit-architectures\u002F",{"guide":297,"slug":384,"title":385,"navOrder":386,"parent":373,"blurb":301,"path":387},"ot-architectures","OT architectures",5.2,"\u002Fapplication-guide\u002Fflowfuse\u002Fot-architectures\u002F",{"guide":297,"slug":389,"title":390,"navOrder":391,"parent":373,"blurb":301,"path":392},"iiot-architectures","IIoT architectures",5.3,"\u002Fapplication-guide\u002Fflowfuse\u002Fiiot-architectures\u002F",{"guide":297,"slug":356,"title":357,"navOrder":394,"parent":301,"blurb":395,"path":396},6,"Start from a use case, break it into apps, and draw the architecture that ties them together — the same method a FlowFuse Proof of Value runs.","\u002Fapplication-guide\u002Fflowfuse\u002Fworked-examples\u002F",{"guide":297,"slug":398,"title":399,"navOrder":400,"parent":356,"blurb":401,"path":402},"worked-example","OEE, end to end",6.1,"One use case — OEE across three lines — broken into two apps and two shared services, then drawn out end to end.","\u002Fapplication-guide\u002Fflowfuse\u002Fworked-example\u002F",1787843652844]