TypeScript implementation of the i3X Beta specification — bridging OPC UA industrial automation to a modern REST API
node-i3x converts OPC UA address spaces into i3X-compliant REST/JSON endpoints. It exposes industrial automation data through a clean HTTP API with:
- Stable element IDs — deterministic, namespace-URI-based identifiers that survive server restarts
- Real-time subscriptions — long-poll and Server-Sent Events (SSE) for live value updates
- Historical data access — query time-series history for any monitored variable
- Two connector modes — connect to a remote OPC UA server over TCP, or embed one in-process with zero network overhead
Built with node-opcua, Fastify, and a hexagonal (ports & adapters) architecture.
Diagram source (mermaid)
graph TB
Client(["☁ HTTP Client"])
subgraph APP["@node-i3x/app — Composition Root"]
direction TB
subgraph INBOUND["INBOUND ADAPTER"]
REST["@node-i3x/rest-server<br/>Fastify routes — i3X Beta API"]
end
subgraph CORE["DOMAIN CORE — ZERO DEPENDENCIES"]
Core["@node-i3x/core<br/>Domain Models · Services · Port Interfaces<br/>Stable IDs · Subscriptions · History"]
end
subgraph OUTBOUND["OUTBOUND ADAPTERS"]
OPC["@node-i3x/opcua-connector<br/>node-opcua client (remote)"]
Pseudo["@node-i3x/pseudo-session-connector<br/>PseudoSession (embedded)"]
end
end
OPCUA(["⚙ OPC UA Server"])
Client <-->|"HTTP / JSON"| REST
REST -->|"uses ports"| Core
Core -->|"IDataSourcePort"| OPC
Core -->|"IDataSourcePort"| Pseudo
OPC <-->|"OPC UA TCP"| OPCUA
Pseudo <-->|"In-process"| OPCUA
| Package | Description | Status |
|---|---|---|
@node-i3x/core |
Domain core: models, ports (IDataSourcePort, ILogger), services (ModelService, ValueService, HistoryService, SubscriptionService), stable ID mapper |
✅ Stable |
@node-i3x/opcua-connector |
OPC UA client adapter — implements IDataSourcePort using node-opcua (remote TCP/binary transport) |
✅ Stable |
@node-i3x/pseudo-session-connector |
PseudoSession adapter — implements IDataSourcePort using node-opcua PseudoSession (embedded in-process, zero network) |
✅ Stable |
@node-i3x/rest-server |
Fastify REST routes implementing the i3X Beta API surface | ✅ Stable |
@node-i3x/app |
Composition root — wires all packages together, entry point | ✅ Stable |
@node-i3x/demo-embedded |
Embedded demo with live dashboard — OPC UA server + i3X API wired via PseudoSession | 🧪 Demo |
# Clone the repository
git clone https://github.com/node-opcua/node-i3x.git
cd node-i3x
# Install dependencies
npm install
# Configure environment
cp .env.example .env
# Edit .env — set NODE_I3X_OPCUA_ENDPOINT to your OPC UA server
# Start in development mode (remote OPC UA)
npm run dev
# Or run the embedded demo (no external OPC UA server needed)
npm run demo -w packages/demo-embeddedThe server starts on http://127.0.0.1:8000 by default. Verify with:
curl http://127.0.0.1:8000/health
# → { "status": "ok" }All configuration is via environment variables (or .env file):
| Variable | Default | Description |
|---|---|---|
NODE_I3X_OPCUA_ENDPOINT |
opc.tcp://localhost:4840 |
OPC UA server endpoint URL |
NODE_I3X_OPCUA_SECURITY_MODE |
None |
Security mode (None, Sign, SignAndEncrypt) |
NODE_I3X_OPCUA_OPTIMIZED_CLIENT |
auto |
auto = detect @sterfive module, disabled = skip |
NODE_I3X_PUBLISH_INTERVAL_MS |
1000 |
OPC UA publishing interval (milliseconds) |
NODE_I3X_SAMPLING_INTERVAL_MS |
250 |
OPC UA sampling interval (milliseconds) |
NODE_I3X_PRELOAD |
true |
Preload the OPC UA model on startup |
NODE_I3X_PRELOAD_STRICT |
false |
Exit if model preload fails |
NODE_I3X_PORT |
8000 |
HTTP server port |
NODE_I3X_HOST |
127.0.0.1 |
HTTP server bind address |
NODE_I3X_LOG_LEVEL |
info |
Log level (debug, info, warn, error) |
# Run all tests (vitest)
npm test
# Run tests in watch mode
npm run test:watch
# TypeScript type checking
npm run typecheck
# Lint + format check (Biome)
npm run lint
# Auto-fix lint and format issues
npm run lint:fix
# Build all packages (tsup — minified ESM + .d.ts)
npm run build| Tool | Purpose |
|---|---|
| TypeScript | Language (ESM-only) |
| tsup | Build (esbuild, minified ESM + .d.ts) |
| Vitest | Testing |
| Biome | Lint + Format |
| Fastify | HTTP framework |
| node-opcua | OPC UA client SDK |
OPC UA NodeId values are volatile — namespace indices can shuffle across server restarts. node-i3x generates stable, deterministic element IDs by:
- Computing the full namespace-URI browse path for each node (e.g.,
nsu=http://example.org;s=Sensor1/Temperature) - Hashing the path with a deterministic hash function
- Producing a fixed-length hex ID that remains constant regardless of namespace index changes
This ensures that REST clients can bookmark and cache element IDs across server lifecycles.
The codebase follows a strict hexagonal / ports & adapters pattern:
@node-i3x/coredefines domain models and port interfaces (IDataSourcePort,ILogger) with zero external dependencies- Outbound adapters (
opcua-connector,pseudo-session-connector) implementIDataSourcePort - Inbound adapter (
rest-server) translates HTTP requests into domain service calls @node-i3x/appis the composition root that wires adapters to ports
| Mode | Package | Transport | Use Case |
|---|---|---|---|
| Remote | @node-i3x/opcua-connector |
OPC UA TCP/Binary | Connect to any standard OPC UA server on the network |
| Embedded | @node-i3x/pseudo-session-connector |
In-process (zero network) | Run an OPC UA server and the i3X API in the same process — ideal for demos, testing, and edge deployments |
The i3X Beta REST API surface:
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/ready |
Readiness check (data source connected?) |
GET |
/v1/info |
Server info, spec version, capabilities |
| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/namespaces |
List all OPC UA namespaces |
| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/objects |
List all objects (optional: ?root=true, ?typeElementId=...) |
POST |
/v1/objects/list |
Bulk-fetch objects by element IDs |
POST |
/v1/objects/value |
Bulk-read current values |
POST |
/v1/objects/related |
Bulk-fetch related objects (children / parent) |
POST |
/v1/objects/history |
Bulk-read historical values |
PUT |
/v1/objects/:elementId/value |
Write a value to a single element |
| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/objecttypes |
List all object types (optional: ?namespaceUri=...) |
| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/relationshiptypes |
List relationship types (stub — 501) |
| Method | Endpoint | Description |
|---|---|---|
POST |
/v1/subscriptions |
Create a new subscription |
POST |
/v1/subscriptions/register |
Register element IDs for monitoring |
POST |
/v1/subscriptions/unregister |
Unregister element IDs |
POST |
/v1/subscriptions/sync |
Poll for value updates (long-poll) |
POST |
/v1/subscriptions/stream |
Stream value updates via SSE |
POST |
/v1/subscriptions/list |
List subscription details |
POST |
/v1/subscriptions/delete |
Delete subscriptions |
📘 Full OpenAPI specification:
openapi.json
docker build -t node-i3x .
docker run -p 8000:8000 \
-e NODE_I3X_OPCUA_ENDPOINT=opc.tcp://host.docker.internal:4840 \
node-i3xFor production deployments, install the optional @sterfive/opcua-optimized-client module for up to 200% performance improvement:
- Intelligent transaction batching
- Automatic server-limit handling
- Advanced auto-healing connection logic
The module is detected automatically at startup — no code changes needed. It is listed as an optionalDependency in @node-i3x/opcua-connector.
Contact Sterfive Support for access.
- Official site: https://i3x.dev
- GitHub: https://github.com/cesmii/i3X
- CESMII: https://cesmii.org
This project is dual-licensed:
| License | Use Case |
|---|---|
| AGPL-3.0-or-later | Open-source use — you must share your source code if you deploy this as a network service |
| Commercial | Proprietary / closed-source use — no copyleft obligations |
The AGPL-3.0 restrictions can be lifted by acquiring a commercial license at sterfive.com.
Contact contact@sterfive.com for pricing and terms.
See LICENSE for full details.
Built by Sterfive — Industrial-grade OPC UA solutions for the modern web.