[{"data":1,"prerenderedAt":403},["ShallowReactive",2],{"application-guide-nav":3,"agmd-node-red-handling-data":118},[4,12,16,22,25,31,36,42,47,53,58,64,70,75,81,87,93,98,103,108,112],{"guide":5,"slug":6,"title":7,"navOrder":8,"parent":9,"blurb":10,"path":11},"flowfuse","overview","Overview",1,null,"The map of the FlowFuse guide — apps, architectures, and a worked example.","\u002Fapplication-guide\u002Fflowfuse\u002Foverview\u002F",{"guide":13,"slug":6,"title":7,"navOrder":8,"parent":9,"blurb":14,"path":15},"node-red","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":5,"slug":17,"title":18,"navOrder":19,"parent":9,"blurb":20,"path":21},"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":13,"slug":17,"title":18,"navOrder":19,"parent":9,"blurb":23,"path":24},"The handful of concepts you need to build with Node-RED, and how they fit together.","\u002Fapplication-guide\u002Fnode-red\u002Ffoundations\u002F",{"guide":5,"slug":26,"title":27,"navOrder":28,"parent":9,"blurb":29,"path":30},"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":13,"slug":32,"title":33,"navOrder":28,"parent":9,"blurb":34,"path":35},"patterns","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":5,"slug":37,"title":38,"navOrder":39,"parent":26,"blurb":40,"path":41},"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":13,"slug":43,"title":44,"navOrder":39,"parent":32,"blurb":45,"path":46},"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":5,"slug":48,"title":49,"navOrder":50,"parent":26,"blurb":51,"path":52},"software-apps","Software apps",3.2,"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":13,"slug":54,"title":55,"navOrder":50,"parent":32,"blurb":56,"path":57},"handling-data","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.","\u002Fapplication-guide\u002Fnode-red\u002Fhandling-data\u002F",{"guide":13,"slug":59,"title":60,"navOrder":61,"parent":32,"blurb":62,"path":63},"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":5,"slug":65,"title":66,"navOrder":67,"parent":9,"blurb":68,"path":69},"data-plane","Data plane",4,"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":13,"slug":71,"title":72,"navOrder":67,"parent":9,"blurb":73,"path":74},"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":13,"slug":76,"title":77,"navOrder":78,"parent":71,"blurb":79,"path":80},"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":13,"slug":82,"title":83,"navOrder":84,"parent":71,"blurb":85,"path":86},"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":5,"slug":88,"title":89,"navOrder":90,"parent":9,"blurb":91,"path":92},"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":5,"slug":94,"title":95,"navOrder":96,"parent":88,"blurb":9,"path":97},"it-architectures","IT architectures",5.1,"\u002Fapplication-guide\u002Fflowfuse\u002Fit-architectures\u002F",{"guide":5,"slug":99,"title":100,"navOrder":101,"parent":88,"blurb":9,"path":102},"ot-architectures","OT architectures",5.2,"\u002Fapplication-guide\u002Fflowfuse\u002Fot-architectures\u002F",{"guide":5,"slug":104,"title":105,"navOrder":106,"parent":88,"blurb":9,"path":107},"iiot-architectures","IIoT architectures",5.3,"\u002Fapplication-guide\u002Fflowfuse\u002Fiiot-architectures\u002F",{"guide":5,"slug":71,"title":72,"navOrder":109,"parent":9,"blurb":110,"path":111},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":5,"slug":113,"title":114,"navOrder":115,"parent":71,"blurb":116,"path":117},"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",{"id":119,"title":55,"blurb":56,"body":120,"description":132,"extension":396,"guide":13,"meta":397,"navOrder":50,"navTitle":55,"navigation":398,"parent":32,"path":399,"seo":400,"slug":54,"stem":401,"__hash__":402},"applicationGuideDoc\u002Fapplication-guide\u002Fnode-red\u002Fhandling-data.md",{"type":121,"value":122,"toc":393},"minimark",[123,126,133,140],[124,125,55],"h1",{"id":54},[127,128,129],"p",{},[130,131,132],"strong",{},"Handling data — classify what you've got, then pick your methods",[127,134,135,136,139],{},"A flow's data isn't one thing. First ",[130,137,138],{},"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.",[141,142,143,235,269,303,353],"guide-tabs",{},[144,145,147,158,161,166,190,195,201,221,226,229],"guide-tab",{"label":146},"Classify the data",[127,148,149,152,153,157],{},[130,150,151],{},"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 ",[154,155,156],"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.",[127,159,160],{},"Every point you touch is some combination of the three:",[127,162,163],{},[130,164,165],{},"By shape — is it an event or a stream?",[167,168,169,180],"ul",{},[170,171,172,175,176,179],"li",{},[130,173,174],{},"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 ",[154,177,178],{},"when it fires"," — you don't poll for it.",[170,181,182,185,186,189],{},[130,183,184],{},"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 ",[154,187,188],{},"at a cadence"," and often only keep the trend.",[127,191,192],{},[130,193,194],{},"By purpose — what is the value for?",[196,197],"flow-diagram",{":edges":198,":nodes":199,"align":200},"[{\"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",[167,202,203,209,215],{},[170,204,205,208],{},[130,206,207],{},"Telemetry"," — readings you observe and trend. Continuous and latency-tolerant: a second late only moves a timestamp.",[170,210,211,214],{},[130,212,213],{},"Control"," — a value that drives a decision or an actuator. Small and time-critical: a second late changes an outcome.",[170,216,217,220],{},[130,218,219],{},"Config"," — a setting that shapes how the app runs. Written rarely, read often.",[127,222,223],{},[130,224,225],{},"By direction — read or write?",[127,227,228],{},"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.",[127,230,231,234],{},[130,232,233],{},"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.",[144,236,238,244,250,254,257,263],{"label":237},"Separate the paths",[127,239,240,243],{},[130,241,242],{},"Telemetry one way, control another"," — give each kind its own route so the fast path never inherits the slow one's load.",[127,245,246,249],{},[154,247,248],{},"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.",[196,251],{":edges":252,":nodes":253,"align":200},"[{\"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}]",[127,255,256],{},"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.",[127,258,259,262],{},[130,260,261],{},"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.",[127,264,265,268],{},[130,266,267],{},"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.",[144,270,272,278,284,289,292,297],{"label":271},"Batch \u002F rate-limit",[127,273,274,277],{},[130,275,276],{},"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.",[127,279,280,283],{},[154,281,282],{},"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.",[196,285],{":edges":286,":nodes":287,":legend":288},"[{\"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\"}]",[127,290,291],{},"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.",[127,293,294,296],{},[130,295,261],{}," — 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.",[127,298,299,302],{},[130,300,301],{},"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.",[144,304,306,312,318,323,326,347],{"label":305},"Hold state in context",[127,307,308,311],{},[130,309,310],{},"One place for state"," — keep a logical object in context instead of threading it through wires.",[127,313,314,317],{},[154,315,316],{},"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.",[196,319],{":edges":320,":nodes":321,":legend":322},"[\"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\"}]",[127,324,325],{},"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.",[127,327,328,330,331,334,335,338,339,342,343,346],{},[130,329,261],{}," — store the object once under a namespaced key at the narrowest scope that works. ",[130,332,333],{},"Node"," scope is private to that one node, so anything ",[154,336,337],{},"shared"," between nodes starts at ",[130,340,341],{},"flow"," scope (then ",[130,344,345],{},"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.",[127,348,349,352],{},[130,350,351],{},"Watch out"," — one writer per key, serialize concurrent updates, and keep enough on the wire to stay debuggable.",[144,354,355,361,367,372,382,387],{"label":219},[127,356,357,360],{},[130,358,359],{},"Static in env vars, runtime in persisted context"," — decide which kind each setting is, then store it accordingly.",[127,362,363,366],{},[154,364,365],{},"Select when — the flow has settings."," The question for each one: does it change per environment at deploy, or while running, by a user?",[196,368],{":edges":369,":nodes":370,":groups":371},"[{\"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\"]}]",[127,373,374,377,378,381],{},[130,375,376],{},"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. ",[130,379,380],{},"Runtime config"," changes while running, by a user, with no redeploy.",[127,383,384,386],{},[130,385,261],{}," — 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.",[127,388,389,392],{},[130,390,391],{},"The rule"," — if a value would ever be changed through a button or form, it is not an env var.",{"title":394,"searchDepth":67,"depth":67,"links":395},"",[],"md",{},true,"\u002Fapplication-guide\u002Fnode-red\u002Fhandling-data",{"title":55,"description":132},"application-guide\u002Fnode-red\u002Fhandling-data","w93FmlxICN8_TOPe0zl1bZ0k8sDYQ8ExGdsaVXm3uzg",1787068106314]