Consuming Data from Other Apps
Every IronFlock app gets a private, isolated data backend: its own tables, its own live streams, its own realm. Isolation is what makes apps safe to install — but on its own it would also make every app a silo. The data a collector app gathers from a machine is valuable far beyond that one app: it is the raw material for dashboards, analytics, machine-learning models, and reports.
Cross-app data access turns installed apps into building blocks. An app can declare that it wants to read the data of another app in the same project — its live event streams and its recorded history. The user who owns the project decides whether to allow it, per app, with a switch they can flip at any time. The platform enforces the rest: access is strictly read-only, scoped to the tables the providing app actually shares, and never crosses project boundaries.
What this makes possible
- Ready-made analytics on top of collectors. Install a data collector on your machines, then install an OEE dashboard app that consumes the collector’s measurements — no integration project, no data export, no glue code.
- Machine learning without plumbing. A predictive-maintenance app can train on months of vibration and temperature history another app already collected, and score live readings as they stream in.
- Specialized apps instead of monoliths. Split collection, transformation, visualization, and reporting into separate apps that each do one thing well — and combine them per project like Lego bricks.
- An ecosystem, not silos. Publish an app whose whole value is what it does with other apps’ data. The App Store listing shows users which data an app shares and which data it requests.
How it works
Three parties are involved, and each keeps control of what is theirs:
- The providing app (“App B”) defines tables and transforms in its
data-template.yml, as every app does. Everything is shareable by default; individual tables can be markedprivate. - The consuming app (“App A”) declares in its
data-template.ymlwhich apps it wants to read from, and why. - The user installs both apps in a project and approves the access — at install time, or later with a per-app switch in the project’s app settings. No approval, no access: the declaration alone grants nothing.
Data never leaves the project. The providing app’s developer still has no access to the user’s data — the grant is between installed apps inside one project, under the project owner’s control.
One standardized project database, many isolated backends
Under the hood, every IronFlock project provisions the same standardized time-series database. Inside it, each installed app owns a private, separated backend space: its tables live in their own database schema, invisible to every other app unless the user grants read access. This one-database-per-project design is what makes the whole model work:
- Reproducible across projects. An app’s data backend is provisioned identically in every project it is installed in — same tables, same types, same query behavior, whether the project runs in the managed cloud or on an on-premises appliance. Build against it once; it behaves the same everywhere.
- A central collection and inspection point. Project owners see all their apps’ data in one place — one database to inspect, query, and own, instead of a scatter of per-app stores.
- Isolation by default, sharing by grant. Schema isolation keeps every app’s space private. A cross-app grant opens a read-only window into another app’s schema — inside the same database, so nothing is copied, exported, or synchronized. The data has one home; access is what changes.
Declaring the dependency
The consuming app announces the apps it reads from in its .ironflock/data-template.yml:
consumes:
- app: machine-monitor
reason: "Computes OEE from the monitor's machine state and counter streams"
data:
tables:
- tablename: oee_results
columns:
# ... your app's own tables, as usualThe app field is the technical app name of the providing app (shown on its App Store page). The reason is displayed to the user in the consent dialog — write it for a human deciding whether to trust your app.
Reading the data
At runtime, the SDK connects to the providing app’s data backend and gives you the same read API you already use for your own tables:
Python
from ironflock import IronFlock
flock = IronFlock()
# Connect to the providing app's data backend (requires the user's grant)
monitor = await flock.connect_to_app("machine-monitor")
# Discover what it shares
print(monitor.tables) # shared tables with their columns
print(monitor.transforms) # shared transforms (views)
# Query history
rows = await monitor.get_history("machinestate", {"limit": 1000})
# Down-sampled series for charts and models
series = await monitor.get_series_history("measurements", {
"metrics": ["temperature"],
"method": "AVG",
"timeRange": ["2026-07-01T00:00:00Z", "2026-07-04T00:00:00Z"],
})
# Subscribe to live rows as they are collected
async def on_row(row):
print("live reading:", row)
await monitor.subscribe_to_table("measurements", on_row)If the user has not granted access (or revokes it later), connectToApp fails with a clear, typed error — your app should treat the data source as optional and degrade gracefully.
Consuming all project data (wildcard)
Some apps are general-purpose data workbenches — a Node-RED runtime, a notebook, a reporting tool — whose whole value is letting the user work with whatever data happens to be in the project. Such an app can’t name providers up front; it doesn’t know which collectors or analytics apps the user will install. For these, declare a wildcard: read access to every app’s data in the project.
consumes:
- app: "*" # the quotes are REQUIRED — a bare * is a YAML alias
reason: "Lets you build flows on the live and historical data of every app in this project"The "*" sentinel grants read access to all apps in the project — including apps the user installs later, with no re-consent. Everything else about the model is unchanged: it’s still read-only, private tables and transforms are still never shared, and platform apps are out of scope. The user approves the wildcard with a single all-or-nothing switch (instead of a per-app list), and can revoke it anytime.
Because a wildcard consumer doesn’t know provider names ahead of time, it discovers them at runtime:
Python
from ironflock import IronFlock
flock = IronFlock()
# Discover every app whose data you may read (name + shared-table catalog)
providers = await flock.list_consumable_apps()
for p in providers:
print(p["app"], p["stages"]) # e.g. "energy-monitor", {"prod": {"tables": [...]}}
# Open one by name (works because you hold the wildcard grant)
energy = await flock.connect_to_app("energy-monitor")
rows = await energy.get_history("meterdata", {"limit": 1000})
# ...or open them all at once
all_apps = await flock.connect_to_all_apps()
for app in all_apps:
await app.subscribe_to_table(app.tables[0]["tablename"], on_row)listConsumableApps() is the primitive — one call, opens no connections, returns each provider’s non-private catalog so you can render a picker. connectToAllApps() is the eager convenience that opens them all. Newly installed apps show up on the next listConsumableApps() call automatically. If the user hasn’t granted the wildcard, both fail with a typed NO_GRANT error.
Read-only by construction
The grant is enforced by the platform’s messaging layer, not by convention. A consuming app can:
| Allowed | Not possible |
|---|---|
| Subscribe to the provider’s live data streams | Write, modify, or delete the provider’s data |
| Query the provider’s recorded history | Call the provider’s custom procedures or commands |
| Read shared transforms (views) | See tables or transforms marked private |
| Discover the shared table catalog | Reach data of apps in other projects |
Sharing your app’s data — and keeping some back
If you build an app that collects valuable data, sharing it is what makes your app a foundation others build on. You don’t have to share everything: mark internal tables or transforms private and they disappear from the shared catalog entirely — not listed, not queryable, not streamed.
data:
tables:
- tablename: measurements # shared (default)
columns: [ ... ]
- tablename: calibration_state # internal — never visible to other apps
private: true
columns: [ ... ]
transforms:
- tablename: hourly_aggregates # shared views work like shared tables
sql: "SELECT ..."The user stays in control
- At install time, the user sees exactly which installed apps the new app wants to read from, and why — and can decline any of them. Declining never blocks the install; the app simply doesn’t get the data.
- Every granted access appears as a switch in the project’s app settings, where it can be revoked (or granted later, e.g. after the providing app is installed) at any time.
- Grants are per project. Installing the same pair of apps in another project starts from zero.
A typical composition
The pattern that makes this concrete — collection, analytics, and visualization as separate, composable apps — is described end-to-end in Factory Data Extraction: protocol collectors extract machine data, and OEE dashboards, predictive-maintenance models, or energy analytics consume it, each installed and permissioned independently.