YAML Definitions — Describing Your Factory as Code
An in-depth look at the UNS Framework standard YAML definitions — how factories are described today inside monolithic vendor tools, why that breaks at scale, and how a set of simple YAML files gives you a version-controlled, human-readable, machine-readable single source of truth for your entire manufacturing namespace. Includes a hands-on walkthrough of describing a small CNC shop from scratch.
- How Factories Are Described Today
- The Monolith Problem at Scale
- Why GitOps for Factory Definitions
- Why YAML
- The UNS Framework Standard Definitions
- Walkthrough: Describing a Small CNC Shop
- Templates & Reuse with YAML Anchors
- Generated MQTT Topics
- From YAML to a Running System
- Scaling to Multiple Sites
- The Bottom Line
How Factories Are Described Today
Every factory has a model of itself — a description of what machines exist, where they are, what they produce, and how data flows between systems. The problem is that this model almost never exists in one place. Instead, it's scattered across half a dozen systems, each with its own partial, incompatible view of reality.
Where Factory Definitions Live Today
| System | What It Knows | Format | Who Can Access It |
|---|---|---|---|
| SCADA / HMI | Tag names, alarm thresholds, screen layouts, PLC addresses | Proprietary binary project files (WinCC, FactoryTalk, Ignition) | The controls engineer who built it |
| MES | Work centres, routings, production orders, equipment IDs | Relational database tables (vendor-specific schema) | The MES administrator |
| ERP | Cost centres, asset numbers, depreciation schedules | SAP/Oracle tables, often with custom fields | Finance and IT |
| CMMS | Equipment hierarchy, maintenance schedules, spare parts | Another vendor database (Maximo, SAP PM, Fiix) | Maintenance team |
| Spreadsheets | Machine lists, IP addresses, sensor mappings, "the master list" | Excel files on a shared drive, emailed between teams | Whoever last saved it |
| Tribal knowledge | "CNC-03 is actually in Bay 4 now, not Bay 2 like the system says" | Someone's head | That one person who's been here 15 years |
The result is that no single system has a complete, accurate, up-to-date description of the factory. The SCADA knows the tag names but not the production context. The MES knows the work centres but not the sensor addresses. The spreadsheet was accurate six months ago. And the person who knows where CNC-03 actually is — they're on holiday.
Manufacturing Engineer
You've spent hours reconciling machine lists between the MES and the SCADA. The MES calls it "MC-2001." The SCADA calls it "CNC_Bay3_Mill." The ERP calls it "Asset 40071." They're all the same machine. Nobody documented the mapping — you just know.
Developer
You're building a dashboard and need to know what machines exist, what data they produce, and what topics to subscribe to. The answer is "ask Dave" or "check the spreadsheet on the S: drive." There's no API, no schema, no documentation you can programmatically consume.
IT Engineer
You need to replicate the MQTT topic structure at a new site. The original was configured manually in the broker and the SCADA over three months. Nobody wrote down the naming conventions. You're reverse-engineering the topic tree from a packet capture.
The Monolith Problem at Scale
Each of those systems — SCADA, MES, ERP, CMMS — is a monolith. It owns its model of the factory, stores it in a proprietary format, and exposes it only through its own interface. This creates five fundamental problems that get worse as you scale.
The Five Problems
| Problem | What Happens | Why It Gets Worse at Scale |
|---|---|---|
| No single source of truth | Every system has a different, partial model. When they disagree — and they always disagree — there's no authoritative answer. | At 1 site with 10 machines, you can keep it in your head. At 5 sites with 500 machines, the inconsistencies multiply exponentially. Nobody knows which system is "right." |
| No version control | Someone changes a tag name in the SCADA, renames a work centre in the MES, or updates the spreadsheet. There's no record of what changed, when, or why. | Configuration drift becomes invisible. Six months later, the dashboard shows wrong data and nobody can trace when it broke. Regulated industries (aerospace, pharma) can't prove compliance. |
| No portability | The factory model is locked inside vendor-specific formats. You can't export your SCADA configuration and import it into a different tool. You can't diff two versions of your MES setup. | Migrating to a new SCADA vendor means rebuilding the entire configuration from scratch. Multi-vendor environments (common at scale) mean maintaining parallel models in incompatible formats. |
| No automation | Adding a new machine means manually updating the SCADA, the MES, the CMMS, the spreadsheet, and the MQTT broker. Each update is a separate, manual, error-prone process. | At scale, "add a machine" becomes a multi-week project involving 4 teams and 6 systems. The overhead of maintaining the model exceeds the value of the model itself. |
| No reproducibility | You can't take the factory definition from Site A and deploy it at Site B. Each site is configured independently, manually, from scratch. | Multi-site rollouts take months instead of minutes. Each site drifts independently. "Standard" configurations are aspirational, not enforced. |
Why GitOps for Factory Definitions
The software industry solved this exact problem 15 years ago. It was called "works on my machine" — every developer had a different environment, configured manually, impossible to reproduce. The solution was infrastructure as code: describe your infrastructure in version-controlled text files, and let tooling make reality match the description.
| Software World | Manufacturing World | The Pattern |
|---|---|---|
| Dockerfile | uns.yml + site.yml | Describe what you have in a text file. The file is the specification. |
| docker-compose.yml | function.yml + mqtt.yml + database.yml | Describe how components connect. Services, endpoints, ports. |
| Kubernetes manifests | UNS Framework YAML definitions | Declarative: describe the desired state, not the steps to get there. |
| Terraform | Multi-site YAML configs | Same definition, different environments. Reproducible deployments. |
git diff |
git diff site.yml |
See exactly what changed, when, and who changed it. |
git revert |
git revert |
Undo any change instantly. Roll back to any previous state. |
The UNS Framework applies this same pattern to manufacturing. Instead of your factory model being trapped inside vendor databases, spreadsheets, and tribal knowledge, it lives in YAML files in a git repository. These files are:
- ✓ Version-controlled — every change has an author, a timestamp, and a commit message explaining why
- ✓ Diff-able —
git diffshows exactly what changed between any two versions - ✓ Reviewable — pull requests let the team review changes before they go live
- ✓ Reproducible —
git cloneat a new site gives you an identical factory definition - ✓ Auditable —
git logprovides a complete, immutable audit trail for regulators - ✓ Machine-readable — any tool, script, or application can parse YAML and act on it
- ✓ Human-readable — an engineer can open the file and understand the factory structure immediately
Without GitOps
"We added CNC-05 last Tuesday. I updated the SCADA and the spreadsheet. I think someone updated the MES. The CMMS still shows the old layout. The MQTT topics were configured manually — I'm not sure if the naming matches the convention we used for the other machines."
With YAML + GitOps
git log --oneline site.yml → a3f2c1d Add CNC-05 to Area 1, Cell 2. One file changed. One commit. The MQTT topics, the naming convention, the sensor model — all defined in the same YAML, all version-controlled, all consistent.
Why YAML
The UNS Framework uses YAML as its definition language. This isn't an arbitrary choice — YAML has specific properties that make it the right format for describing manufacturing infrastructure.
YAML vs Alternatives
| Format | Human-Readable | Machine-Readable | Supports Hierarchy | Templates / Reuse | Industry Adoption |
|---|---|---|---|---|---|
| YAML | ✓ Excellent — indentation-based, minimal syntax | ✓ Parsers in every language | ✓ Native nesting | ✓ Anchors & aliases (& / *) |
Docker Compose, Kubernetes, GitHub Actions, Ansible, CloudFormation |
| JSON | Moderate — brackets and quotes add noise | ✓ Universal | ✓ Native nesting | ✗ No native reuse mechanism | APIs, config files, data exchange |
| XML | Poor — verbose, tag-heavy | ✓ Mature parsers | ✓ Native nesting | Partial (XInclude, entities) | Legacy enterprise, OPC UA, B2MML |
| TOML | Good for flat config | ✓ Growing support | Limited — deep nesting is awkward | ✗ No native reuse | Rust ecosystem, some config files |
| Proprietary binary | ✗ Requires vendor tool | ✗ Vendor-locked | Varies | Varies | SCADA, PLC, MES vendor tools |
YAML wins on the combination that matters most for factory definitions: a manufacturing engineer can read and edit it without special tools, while any software system can parse and act on it programmatically. It's the same reason Docker chose YAML for Compose files and Kubernetes chose it for manifests — the format disappears, and you focus on what you're describing.
Key YAML Features for Factory Definitions
# 1. Hierarchy maps naturally to ISA-95 site: - name: Detroit area: - name: Machining line: - name: CNC Line 1 cell: - name: Cell A # 2. Anchors eliminate repetition template_cnc: &cnc_sensor information_model: status: { data_type: string } spindle_speed: { data_type: float } # 3. Aliases reuse templates — DRY principle sensors: - id: S1 <<: *cnc_sensor # Inherits the full template - id: S2 <<: *cnc_sensor # Same template, different sensor # 4. Comments document intent — crucial for team collaboration # Added 2026-03-15 — new mill installed in Cell A # Approved by: J. Smith (maintenance) + M. Chen (controls)
The UNS Framework Standard Definitions
The UNS Framework defines a set of standard YAML definition types that together describe your entire manufacturing namespace. Each definition type maps to a specific concept in the ISA-95 hierarchy or the supporting infrastructure. Think of them as building blocks — you compose them to describe your specific factory.
The Definition Types
| Definition | File | What It Describes | ISA-95 Level |
|---|---|---|---|
| UNS | uns.yml |
The namespace itself — name, region, timezone, topic structure, topic standard, information model | Enterprise |
| Site | site.yml |
A physical or logical location — factory, plant, building | Level 4 — Site |
| Area | site.yml |
A subdivision within a site — building, floor, department, bay | Level 3 — Area |
| Line | site.yml |
A production line within an area | Level 3 — Line |
| Cell | site.yml |
A workstation or unit within a line | Level 2 — Cell |
| Equipment | site.yml |
A machine, device, or hardware that performs tasks | Level 1 — Equipment |
| Sensor | site.yml |
A data source attached to equipment — temperature, pressure, status, position | Level 0 — Sensor |
| Function | function.yml |
A self-contained block of code that processes data in the namespace | Processing |
| Producer | producer.yml |
An entity that sends data into the namespace — PLC gateway, Node-RED flow, OPC UA client | Data source |
| Consumer | consumer.yml |
An entity that receives data from the namespace — ERP, MES, dashboard, analytics | Data sink |
| MQTT | mqtt.yml |
The MQTT broker — host, port, credentials | Infrastructure |
| Database | database.yml |
The database for historical storage — host, port, credentials | Infrastructure |
| Artifact | artifact.yml |
Static data and reusable templates — equipment specs, sensor catalogues | Reference data |
How They Map to ISA-95
The physical hierarchy definitions (Site → Area → Line → Cell → Equipment → Sensor) map directly to the ISA-95 equipment hierarchy standard. This isn't accidental — ISA-95 is the most widely adopted standard for describing manufacturing operations, and the UNS Framework's YAML structure mirrors it exactly.
Walkthrough: Describing a Small CNC Shop
Let's build a complete set of UNS Framework YAML definitions from scratch. We'll describe a small CNC machining shop with 2 machines in 1 area — enough to see every definition type in action, small enough to understand completely.
The Physical Reality
Our shop has:
- • 1 site — a factory in Detroit
- • 1 area — the machining department
- • 1 line — CNC Line 1
- • 1 cell — Cell A (a group of machines that work together)
- • 2 machines — a Haas VF-2 mill (cnc-01) and a DMG Mori lathe (cnc-02)
- • 1 sensor per machine — each publishing status, spindle speed, program, and tool data
- • 1 environment sensor — temperature monitoring in the cell
- • 1 MQTT broker — Eclipse Mosquitto running locally
- • 1 database — PostgreSQL for historical storage
- • 2 functions — state tracking and historical logging
- • 1 producer — a Node-RED flow reading from the PLCs
- • 1 consumer — the ERP system pulling production data
Step 1: uns.yml — Define the Namespace
Start with the namespace itself. This file describes the top-level configuration — what version of the standard you're using, the topic structure, and the information model.
# uns.yml — the namespace definition # This is the root of your factory-as-code description. version: '1.0' uns: name: 'Detroit CNC Shop' region: 'US' timezone: 'America/Detroit' topic_structure: 'version/site/area/line/cell/equipment/sensor/information_model/' topic_standard: 'ISA95' information_model: 'User Defined'
This tells anyone — human or machine — that this namespace follows ISA-95, uses a versioned topic structure, and is located in the US Eastern timezone. The topic_structure field is the blueprint for how every MQTT topic in the namespace will be constructed.
Step 2: site.yml — Describe the Physical Hierarchy
This is the most important file — it describes the physical structure of your factory, from site down to individual sensors. The hierarchy is nested, just like the physical reality.
# site.yml — the physical hierarchy # Site → Area → Line → Cell → Equipment → Sensors version: '1.0' # ── Templates (defined once, reused everywhere) ────────────── template_equipment: &template_equipment dataops: normalization: units: 'mm' transformation: timezone: 'utc' template_sensor_cnc: &template_sensor_cnc information_model: status: data_type: string # ACTIVE, IDLE, ALARM, SETUP, OFFLINE spindle_speed: data_type: float # RPM feed_rate: data_type: float # mm/min program: data_type: string # Current program name tool: data_type: string # Current tool ID spindle_load: data_type: float # Percentage template_sensor_env: &template_sensor_env information_model: temperature: data_type: float # Celsius humidity: data_type: float # Percentage # ── Physical Hierarchy ──────────────────────────────────────── site: - name: Detroit id: detroit location: 'Detroit, MI, USA' area: - name: Machining id: machining line: - name: CNC Line 1 id: line1 cell: - name: Cell A id: cell-a equipment: - id: 'cnc-01' name: 'Haas VF-2 Mill' <<: *template_equipment sensors: - id: 's1' <<: *template_sensor_cnc - id: 'cnc-02' name: 'DMG Mori NLX 2500' <<: *template_equipment sensors: - id: 's2' <<: *template_sensor_cnc - id: 'env-01' name: 'Environment Sensor' sensors: - id: 's3' <<: *template_sensor_env
Step 3: mqtt.yml — Describe the Broker
# mqtt.yml — MQTT broker configuration version: '1.0' mqtt: broker: host: 'mqtt://mqtt.detroit-factory.local' port: 1883 username: 'uns-service' password: '${MQTT_PASSWORD}' # Use env var for secrets
Step 4: database.yml — Describe the Historian
# database.yml — historical storage configuration version: '1.0' database: timeseries: host: 'postgres.detroit-factory.local' port: 5432 username: 'uns' password: '${DATABASE_PASSWORD}'
Step 5: function.yml — Describe the Processing Functions
# function.yml — data processing functions version: '1.0' function: - name: uns-state endpoint: http://uns-state:8080 # Tracks machine state transitions (ACTIVE → IDLE → ALARM) - name: uns-historian endpoint: http://uns-historian:8080 # Logs every value change to PostgreSQL - name: uns-kpi endpoint: http://uns-kpi:8080 # Calculates OEE, availability, performance
Step 6: producer.yml & consumer.yml — Describe Data Flow
# producer.yml — entities that send data into the namespace version: '1.0' producer: - name: Node-RED-PLC-Gateway endpoint: http://nodered.detroit-factory.local:1880 # Reads Modbus from both CNCs, publishes to MQTT
# consumer.yml — entities that receive data from the namespace version: '1.0' consumer: - name: ERP-Production-Sync endpoint: opcua://erp.detroit-factory.local:4840 # Pulls production counts and cycle times into ERP
The Complete File Structure
# Your factory, described as code detroit-uns/ ├── uns.yml # Namespace: version, region, topic structure ├── site.yml # Physical: site → area → line → cell → equipment → sensors ├── mqtt.yml # Infrastructure: MQTT broker connection ├── database.yml # Infrastructure: PostgreSQL connection ├── function.yml # Processing: functions that act on the data ├── producer.yml # Data flow: what sends data in ├── consumer.yml # Data flow: what reads data out └── README.md # Documentation for the team # Total: 7 YAML files. Your entire factory in a git repository. # Any engineer can read it. Any tool can parse it. # Every change is tracked. Every version is recoverable.
Templates & Reuse with YAML Anchors
In a real factory, you don't have one machine — you have dozens or hundreds, many of the same type. Without templates, you'd copy-paste the same sensor definition for every machine. YAML anchors and aliases solve this elegantly.
How Anchors Work
# Step 1: Define the template with an anchor (&) template_sensor_cnc: &template_sensor_cnc information_model: status: data_type: string spindle_speed: data_type: float feed_rate: data_type: float program: data_type: string tool: data_type: string spindle_load: data_type: float # Step 2: Reuse with an alias (*) and merge key (<<:) equipment: - id: 'cnc-01' sensors: - id: 's1' <<: *template_sensor_cnc # ← All 6 fields inherited - id: 'cnc-02' sensors: - id: 's2' <<: *template_sensor_cnc # ← Same 6 fields, no copy-paste - id: 'cnc-03' sensors: - id: 's3' <<: *template_sensor_cnc # ← And again. Define once, use everywhere.
Why Templates Matter at Scale
| Scenario | Without Templates | With Templates |
|---|---|---|
| 10 identical CNC machines | Copy-paste the sensor definition 10 times. 60+ lines of duplicated YAML. | Define the template once (6 lines). Reference it 10 times (1 line each). 16 lines total. |
| Change the information model | Find and update all 10 copies. Miss one? That machine's data is now inconsistent. | Update the template once. All 10 machines inherit the change automatically. |
| Add a new sensor field | Add it to all 10 copies manually. Hope you don't introduce a typo in copy #7. | Add it to the template. Done. Every machine that references the template gets the new field. |
| New site with same machine types | Copy the entire site.yml. The templates are embedded in the copy — changes don't propagate. | The new site references the same templates. Consistency is guaranteed by the YAML structure. |
Templates can also be composed. An equipment template defines dataops (normalisation, transformation), while a sensor template defines the information model. Combine them for a complete machine definition:
# Equipment template — how to process the data template_equipment: &template_equipment dataops: normalization: units: 'mm' scale: 1.0 transformation: timezone: 'utc' aggregation: method: 'average' window: 60 # Sensor template — what data the sensor produces template_sensor_cnc: &template_sensor_cnc information_model: status: { data_type: string } spindle_speed: { data_type: float } # Compose both templates on a single machine equipment: - id: 'cnc-01' name: 'Haas VF-2 Mill' <<: *template_equipment # ← Inherits dataops sensors: - id: 's1' <<: *template_sensor_cnc # ← Inherits information model
Generated MQTT Topics
The YAML definitions don't just document your factory — they define the MQTT topic tree. Each level of the hierarchy becomes a segment in the topic path, following the topic_structure defined in uns.yml.
From our walkthrough example, the following MQTT topics are generated:
CNC-01 (Haas VF-2 Mill)
v1.0/detroit/machining/line1/cell-a/cnc-01/s1/status v1.0/detroit/machining/line1/cell-a/cnc-01/s1/spindle_speed v1.0/detroit/machining/line1/cell-a/cnc-01/s1/feed_rate v1.0/detroit/machining/line1/cell-a/cnc-01/s1/program v1.0/detroit/machining/line1/cell-a/cnc-01/s1/tool v1.0/detroit/machining/line1/cell-a/cnc-01/s1/spindle_load
CNC-02 (DMG Mori NLX 2500)
v1.0/detroit/machining/line1/cell-a/cnc-02/s2/status v1.0/detroit/machining/line1/cell-a/cnc-02/s2/spindle_speed v1.0/detroit/machining/line1/cell-a/cnc-02/s2/feed_rate v1.0/detroit/machining/line1/cell-a/cnc-02/s2/program v1.0/detroit/machining/line1/cell-a/cnc-02/s2/tool v1.0/detroit/machining/line1/cell-a/cnc-02/s2/spindle_load
Environment Sensor
v1.0/detroit/machining/line1/cell-a/env-01/s3/temperature v1.0/detroit/machining/line1/cell-a/env-01/s3/humidity
Functions
v1.0/fn/uns-state v1.0/fn/uns-historian v1.0/fn/uns-kpi
Every topic is deterministic — given the YAML definitions, you can compute the exact topic tree. No manual configuration, no guessing, no "ask Dave." The YAML is the specification, and the topics are the implementation.
From YAML to a Running System
The YAML definitions are not just documentation — they're the contract between every component in your system. Here's how the definitions connect to a running fn-uns deployment.
How Each Component Uses the Definitions
| Component | Reads From | What It Does With It |
|---|---|---|
| uns-sim (simulator) | config.yaml (derived from site.yml) |
Generates realistic machine data for every equipment and sensor defined. The simulator's config mirrors the site hierarchy — areas, machines, sensors, programs. |
| uns-framework | MQTT wildcard v1.0/# |
Subscribes to the entire namespace. The topic structure defined in uns.yml determines what the framework sees. New machines appear automatically — no configuration change needed. |
| uns-state / uns-historian | Valkey cache + PostgreSQL | The cache keys and database columns follow the topic structure. The YAML defines the namespace; the functions process whatever appears in it. |
| uns-input | config.yaml |
The operator input screen is configured with YAML — reason codes, categories, theme colours, API endpoints. Same pattern: describe what you want, the system implements it. |
| Dashboards | PostgreSQL queries | Dashboard queries reference the topic structure. The YAML definitions ensure consistent naming — the dashboard knows that cnc-01 in the database matches cnc-01 in the YAML. |
| New developers | The YAML files directly | A new team member opens site.yml and immediately understands the factory structure — what machines exist, where they are, what data they produce. No tribal knowledge required. |
Manufacturing Engineer
When you add a new machine to the shop floor, you add it to site.yml. That single change propagates everywhere — the simulator generates data for it, the framework processes it, the dashboard shows it. One file, one change, one source of truth.
Developer
You're building a new function and need to know the topic structure? Open uns.yml. Need to know what sensors exist on cnc-01? Open site.yml. Need the database connection? Open database.yml. Everything is documented, parseable, and version-controlled. No more "ask Dave."
IT Engineer
Deploying to a new site? git clone the repository, update the site-specific values in the YAML files (broker address, database credentials, site name), and docker compose up. The entire namespace is defined in the files — no manual broker configuration, no manual topic setup.
Scaling to Multiple Sites
The real power of YAML definitions becomes clear when you scale beyond a single site. Adding a second factory is not a new project — it's a new set of YAML files in the same repository.
Adding a Second Site
# site.yml — now with two sites version: '1.0' # Templates are shared across all sites template_sensor_cnc: &template_sensor_cnc information_model: status: { data_type: string } spindle_speed: { data_type: float } feed_rate: { data_type: float } program: { data_type: string } tool: { data_type: string } spindle_load: { data_type: float } site: # ── Site 1: Detroit ────────────────────────────────────── - name: Detroit id: detroit location: 'Detroit, MI, USA' area: - name: Machining id: machining line: - name: CNC Line 1 id: line1 cell: - name: Cell A id: cell-a equipment: - id: 'cnc-01' name: 'Haas VF-2 Mill' sensors: - id: 's1' <<: *template_sensor_cnc - id: 'cnc-02' name: 'DMG Mori NLX 2500' sensors: - id: 's2' <<: *template_sensor_cnc # ── Site 2: Munich ─────────────────────────────────────── - name: Munich id: munich location: 'Munich, Bavaria, Germany' area: - name: Precision Machining id: precision line: - name: 5-Axis Line id: 5axis cell: - name: Cell 1 id: cell-1 equipment: - id: 'cnc-10' name: 'DMG Mori DMU 50' sensors: - id: 's10' <<: *template_sensor_cnc - id: 'cnc-11' name: 'Hermle C 400' sensors: - id: 's11' <<: *template_sensor_cnc
The git diff for this change tells the whole story:
# git diff site.yml + # ── Site 2: Munich ─────────────────────────────────────── + - name: Munich + id: munich + location: 'Munich, Bavaria, Germany' + area: + - name: Precision Machining + ... # git log --oneline b7e4a2f Add Munich site — 5-axis line with DMU 50 and Hermle C 400 a3f2c1d Initial Detroit site — 2 CNCs in Cell A
Multi-Site Topic Namespacing
Because the site ID is part of the topic path, topics from different sites are naturally namespaced:
# Detroit topics v1.0/detroit/machining/line1/cell-a/cnc-01/s1/status v1.0/detroit/machining/line1/cell-a/cnc-02/s2/status # Munich topics v1.0/munich/precision/5axis/cell-1/cnc-10/s10/status v1.0/munich/precision/5axis/cell-1/cnc-11/s11/status # Subscribe to everything at one site v1.0/detroit/# # Subscribe to everything across all sites v1.0/#
Without YAML Definitions
Adding a second site means: fly someone to Munich, manually configure the MQTT broker, manually set up the SCADA tags, manually create the database tables, manually build the dashboards, hope the naming conventions match Detroit, document everything in a spreadsheet that will be outdated by next month.
With YAML + GitOps
Adding a second site means: add a new site entry to site.yml, commit, push. The templates guarantee the same information model. The topic structure guarantees consistent naming. The git history documents when Munich was added and by whom. Deploy with git clone + docker compose up.
The Bottom Line
Your factory has a structure. Today, that structure is described inside vendor databases, spreadsheets, and people's heads — fragmented, unversioned, and impossible to reproduce. The UNS Framework standard gives you a better way.
| Property | Monolithic Vendor Tools | UNS Framework YAML |
|---|---|---|
| Source of truth | Scattered across 6+ systems, each with a partial view | One set of YAML files in a git repository |
| Version control | None — changes are invisible and untrackable | Full git history — every change has an author, date, and reason |
| Portability | Locked in vendor-specific binary formats | Plain text YAML — readable by any tool, any language, any platform |
| Reproducibility | Manual configuration at each site, each time | git clone → identical factory definition, instantly |
| Collaboration | "Ask Dave" / check the spreadsheet on the shared drive | Pull requests, code review, comments in the YAML itself |
| Automation | Manual updates across multiple systems for every change | Tools parse the YAML and act on it — topics, configs, dashboards derived automatically |
| Auditability | No trail — "who changed the tag name?" is unanswerable | git log + git blame — cryptographically signed, immutable history |
| Multi-site scaling | Months of manual configuration per site | Add a site entry to site.yml, push, deploy. Templates guarantee consistency. |
| Cost | Vendor licenses per site, per device, per user | Free — open standard, open source, plain text files |
Next Steps
| Resource | Description |
|---|---|
| UNS Framework Standard | The complete standard documentation — every definition type, every parameter, every schema |
| Core Definitions | Detailed reference for all 13 definition types |
| Full Example | A complete example deployment with all YAML files and generated MQTT topics |
| Digital Twins & GitOps | How YAML definitions and GitOps enable composable digital twins |
| Flow vs GitOps | When to graduate from Node-RED experiments to production GitOps |
| Getting Started | Deploy the fn-uns reference pipeline — see the YAML definitions in action |
Guide Version: 1.0 · Applies To: UNS Framework Standard v1.0, YAML definitions, GitOps, ISA-95 topic hierarchy
Last updated March 2026.