node-opcua - Pure Node.js OPC UA SDK
node-opcua is a comprehensive, pure JavaScript/TypeScript implementation of the OPC Unified Architecture (OPC UA) stack, designed for Node.js environments. It enables the creation of OPC UA clients, servers, and related tools, facilitating machine-to-machine (M2M) and Industrial IoT (IIoT) communication. The package is actively maintained, with frequent minor and patch releases, currently stable at version 2.169.0, focusing on performance, memory optimization, and OPC UA 1.05 compliance. Key differentiators include its full adherence to the OPC UA specification, a robust architecture for handling large information models, and enterprise-grade support and value-added extensions provided by Sterfive SAS, which also sponsors its long-term development. It supports modern Node.js versions (>=18) and ships with TypeScript types for improved developer experience.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
cause Attempting to use `require()` to import `node-opcua`, which is primarily an ES Module package, or the build output is configured as ESM.fixMigrate your project or the specific file to use ES Module `import` syntax (`import { Name } from 'node-opcua';`). Ensure your `package.json` has `"type": "module"` if using `.js` files for ESM, or use `.mjs` extensions. -
Error: self signed certificate in certificate chain
cause The client or server is configured to validate certificates strictly, but it encountered a self-signed certificate that is not in its trusted certificate store, or the certificate chain cannot be verified.fixFor development, set `securityMode: MessageSecurityMode.None` and `securityPolicy: SecurityPolicy.None` (if applicable) or `allowAnonymous: true` on the server. For production, generate valid certificates from a trusted CA, ensure all certificates in the chain are in the respective trust lists, or utilize a Global Discovery Server (GDS) for certificate management. -
Error: connect ECONNREFUSED
cause The OPC UA client failed to establish a network connection to the server. This typically means the server is not running, the endpoint URL (IP/port) is incorrect, or a firewall is blocking the connection.fixVerify the OPC UA server is running and listening on the specified port. Double-check the client's `endpointUrl` for correctness. Ensure no firewall rules (local or network) are blocking TCP traffic on the server's port. For Docker/NAT, ensure advertised endpoints are correctly configured. -
[NODE-OPCUA-W06] server : server certificate doesn't match the Server settings
cause The application URI or hostname configured in the server's settings does not match the information embedded in its generated certificate, leading to potential client rejection.fixDelete the auto-generated certificate files (typically found in `C:\Users\user\AppData\Roaming\node-opcua-default-nodejs` on Windows or `~/.config/node-opcua-default-nodejs` on Linux) and restart the server to regenerate them with the correct host information. For custom certificates, ensure the certificate's subject alternative names (SANs) or common name (CN) match the server's application URI and hostname.
Warnings
- breaking Node.js engine requirement updated to >=18. Applications running on older Node.js versions will cease to function or exhibit instability with current node-opcua releases.
- breaking Core packages fully migrated from `async`/`lodash` to native modern JavaScript patterns. If you had relied on internal utilities exposed from these previously, your code may break. This also affects the `node-opcua-pki` package, which had public API changes.
- breaking Significant changes to certificate management architecture and APIs, particularly in `node-opcua-pki` (v6.0.0+), include sanitization of public API and new certificate validation options. Existing certificate management code may require updates.
- breaking Default security policies on the server have changed to `Aes256_Sha256_RsaPss` (OPC UA 1.05 compliant), removing `Basic128Rsa15` and `Basic256` from defaults. Clients connecting to servers with default configurations may need to adjust their security policy.
- gotcha For Node.js versions newer than 18.11.1 or >20.11.1, enabling PKCS1 padding (reintroduced in v2.123.0) requires the `--security-revert=CVE-2023-46809` argument when running Node.js. This reverses a security fix and should be used with caution.
- gotcha Advanced documentation and technical support, as well as several value-added extensions (e.g., PubSub, WebProxy, GDS, React components), are provided exclusively to registered members of the NodeOPCUA Subscription or through dedicated Professional Services.
- gotcha When deploying in environments using Docker, NAT, or reverse proxies, correctly configuring 'Advertised Endpoints' (introduced in v2.165.0) is crucial to ensure clients can discover and connect to the server with the correct network addresses. Misconfiguration can lead to `ECONNREFUSED` or `Bad_TcpEndpointUrlInvalid` errors.
Install
-
npm install node-opcua -
yarn add node-opcua -
pnpm add node-opcua
Imports
- OPCUAClient
const OPCUAClient = require('node-opcua').OPCUAClient;import { OPCUAClient } from 'node-opcua'; - OPCUAServer
const OPCUAServer = require('node-opcua').OPCUAServer;import { OPCUAServer } from 'node-opcua'; - DataType, AttributeIds
import { ClientSession } from 'node-opcua/dist/schemas';import { DataType, AttributeIds } from 'node-opcua';
Quickstart
import { OPCUAServer, OPCUAClient, MessageSecurityMode, SecurityPolicy, DataType, Variant, AttributeIds } from "node-opcua";
import { resolve } from "path";
// --- Server Setup ---
async function startServer() {
// Ensure a 'certificates' directory exists in your project root
// For production, manage certificates securely (e.g., via GDS)
// This example uses anonymous authentication for simplicity.
const server = new OPCUAServer({
port: 4334,
resourcePath: "/UA/MySampleServer",
buildInfo: {
productName: "MySampleServer",
buildNumber: "1234",
buildDate: new Date()
},
serverInfo: {
applicationUri: "urn:MySampleServer",
productUri: "urn:MySampleServer",
applicationName: { text: "MySampleServer", locale: "en" }
},
securityModes: [MessageSecurityMode.None],
securityPolicies: [SecurityPolicy.None],
allowAnonymous: true,
// Certificate files are needed even with securityMode.None in many setups
// The toolkit generates default ones in C:\Users\user\AppData\Roaming\node-opcua-default-nodejs
// if not provided, but explicitly setting them is good practice for production.
// For simplicity in this quickstart, we assume default generation or manual placement.
});
await server.start();
console.log(`Server started on port ${server.port}`);
console.log(`Server endpointUrl: ${server.endpointUrl}`);
server.engine.addressSpace?.getFolder("ObjectsFolder")?.addVariable({
nodeId: "ns=1;s=MyDynamicVariable",
browseName: "MyDynamicVariable",
dataType: DataType.Int32,
value: {
get: () => new Variant({ dataType: DataType.Int32, value: Math.floor(Math.random() * 100) })
}
});
return server;
}
// --- Client Setup ---
async function startClient(endpointUrl: string) {
const client = OPCUAClient.create({
endpointUrl,
securityMode: MessageSecurityMode.None,
securityPolicy: SecurityPolicy.None,
connectionStrategy: {
maxRetry: 0, // No retries for quickstart simplicity
initialDelay: 100
}
});
try {
await client.connect(endpointUrl);
console.log("Client connected to server.");
const session = await client.createSession();
console.log("Client session created.");
// Browse the root folder
const browseResult = await session.browse("RootFolder");
console.log("RootFolder children:");
for (const reference of browseResult.references || []) {
console.log(` - ${reference.browseName.toString()}`);
}
// Read the value of MyDynamicVariable
const readValue = await session.read({
nodeId: "ns=1;s=MyDynamicVariable",
attributeId: AttributeIds.Value
});
console.log(`Value of MyDynamicVariable: ${readValue.value?.value}`);
await session.close();
await client.disconnect();
console.log("Client disconnected.");
} catch (err) {
console.error("Client error:", err);
}
}
// --- Main Execution ---
(async () => {
let server: OPCUAServer | null = null;
try {
server = await startServer();
// Give server a moment to fully initialize
await new Promise(resolve => setTimeout(resolve, 1000));
await startClient(server.endpointUrl!); // Use the server's dynamically assigned endpoint
} catch (error) {
console.error("Error during quickstart execution:", error);
} finally {
if (server) {
console.log("Shutting down server...");
await server.shutdown();
console.log("Server shut down.");
}
}
})();