Smart functions provide a lightweight way to extend the functionality of Cumulocity across multiple components. They let you write small Javascript functions that run in a secure, isolated environment — more powerful than configuration but much simpler than building a full microservice.
Use smart functions to process data, transform messages, create analytics, or customize behavior without managing complex deployment infrastructure. Whether you’re preparing data before it enters the system, building analytics models, or processing messages at the edge, smart functions offer a unified approach with consistent security and performance.
Explore the topics below to understand how smart functions work across different components and when to use them.
Overview
What are smart functions?
Smart functions are a consistent extension approach built into Cumulocity. They let you embed custom Javascript logic directly into platform components—without building or deploying a custom microservice.
Think of them as function-as-a-service for the Internet of Things: each smart function is a focused piece of logic that runs inside a platform component, triggered by the component at the right moment. You write the function, configure it in the UI, and the platform handles execution, security, and scaling.
Smart functions sit between two extremes. They are more powerful and flexible than static configuration, letting you apply custom logic to your data and workflows. At the same time, they are far simpler than microservices—there is no container to build, no infrastructure to manage, and no separate deployment pipeline.
How smart functions are deployed
Smart functions do not exist in isolation. Each component has its own object type that you create, configure, and manage, and smart functions are embedded within it. For example:
In Data Preparation, the object is a rule. Each rule contains exactly one smart function, which is applied to every message that the rule matches.
In Streaming Analytics, the object is a model. A model defines a processing pipeline made up of connected blocks. Smart functions appear as one type of block within that pipeline, alongside built-in blocks for filtering, aggregation, and output. A model can contain any number of blocks, including multiple smart function blocks.
In thin-edge.io, the object is a flow. A flow defines a message-processing pipeline on the edge device and can include one or more smart functions at different stages.
You create and manage rules, models, and flows through each component’s UI or API. The smart functions inside them are written in Javascript and executed by the platform.
Key advantages
A consistent extension approach across the platform
Smart functions follow the same concepts and patterns wherever they appear. Learn the model once, and apply it across Data Preparation, Streaming Analytics, thin-edge.io, and future components. This consistency also reduces the learning required to build end-to-end solutions: the same mental model, tooling, and development workflow applies whether you are writing logic for the cloud or the edge.
Easy movement of logic between cloud and edge
Because smart functions share the same language and API patterns across components, it is straightforward to move business logic between environments. A transformation written for Data Preparation in the cloud can be adapted for a thin-edge.io flow on the device, without switching languages or development tools.
Standard tooling for development and packaging
Smart functions use standard Javascript tooling. You can write them in any editor, use TypeScript for type safety, and bundle external libraries using any standard Javascript build tool. The same workflow and packaging approach applies regardless of which component you are targeting.
Lighter weight than custom microservices
Microservices are the right tool when you need a fully independent service with its own lifecycle. Smart functions are the right tool when you need targeted custom logic embedded in an existing component. There is no container orchestration, no dependency management, and no complex CI/CD pipeline—just a Javascript function deployed as part of a rule, model, or flow.
Integrated into platform components and UI
Smart functions are first-class citizens of each component. Many components allow you to write and manage them through the component’s own UI, in addition to using common external development tooling.
Automatically scalable and secure
The platform handles execution of smart functions, automatically scaling them as needed and ensuring they run securely in a sandboxed environment. You can focus on writing your logic without worrying about infrastructure, security, or performance.
AI-assisted development
Smart functions are designed to work well with AI code generation. The function signatures are simple and well-typed, which makes them easy to describe to an AI tool and easy to review. Where components provide an in-platform editing experience, AI assistance is integrated directly into the editor, allowing you to generate, refine, and explain smart functions without leaving the platform.
Secure by design
Smart functions run in a sandboxed environment. They cannot access the host filesystem, open network connections, or read another tenant’s data. Resource consumption is bounded by the platform. For details, see Sandbox and limits.
How smart functions fit into Cumulocity
Data Preparation uses smart functions inside rules to transform inbound device messages before sending the result into the platform, enabling data normalization, enrichment, and filtering at ingestion time.
Streaming Analytics uses smart functions as custom blocks inside models, allowing you to apply business logic to real-time data streams.
thin-edge.io uses smart functions inside flows to process messages at the edge, reducing bandwidth and enabling local processing before data reaches the cloud.
Other components will add smart functions support over time, each applying the pattern to their domain.
For more details on the different implementations, see Implementations.
Common features
Every smart function in Cumulocity follows a consistent API, regardless of whether it runs in Data Preparation, Streaming Analytics, thin-edge.io, or another component. This section covers the features and patterns that apply to all implementations.
Function signature
A smart function exports a single named function as the entry point. The function name depends on the component (for example, onMessage for Data Preparation or onInput for Streaming Analytics), but the pattern is always the same:
export [async] function FUNCTION_NAME(arg1, arg2, ..., context) {
// Your logic here
return result;
}
The final parameter is always a context object provided by the system. This object gives your function access to runtime information and utilities it may need.
Language and runtime
Smart functions run in a Javascript runtime and support ECMAScript 2023 features. Some components allow you to write Javascript code directly within the platform in the Cumulocity UI. Alternatively, you can write and transpile your code outside the platform—using Javascript directly or TypeScript with your own build toolchain—and upload the resulting Javascript file for execution.
Supported language features include:
Arrow functions, destructuring, spread operators, and other modern syntax
Template literals, classes, modules, and more
Standard library
In addition to the standard library features within the ES2023 standard, all smart functions also provide a Console API: console.log(), console.info(), console.warn(), console.error(), and console.debug() for logging messages visible in the system.
Some components may provide other libraries in addition depending on the needs of that component.
These utilities are sufficient for most common tasks. If you need additional functionality, you can deploy additional libraries with all smart functions via transpilation when you write your code outside of the platform. On a per-component-basis it may also be possible to provide further libraries that can be included at runtime within the Javascript.
Context object
The context parameter provides access to system-supplied information and utilities:
exportfunction onMessage(message, context) {
console.log('Runtime:', context.runtime);
// Your function can access runtime details and any implementation-specific utilities
return message;
}
All smart functions receive a context object with a runtime property that identifies the execution environment (for example, "data-preparation" or "streaming-analytics"). Different implementations may add additional functions and properties to the context for component-specific functionality.
Asynchronous operations
You can define smart functions as async to support asynchronous operations:
The system automatically handles both synchronous and asynchronous function signatures. Async functions should return promises that resolve to the expected output type for your implementation. By default, no unfulfilled promises can be created within a smart function runtime, so use of async is purely for convenience with APIs, they cannot actually run asynchronously. Some implementations may provide true asynchronous operations.
No global state
Each invocation of your smart function runs in isolation. You must not rely on global variables or state that persists between invocations. Every execution receives fresh inputs, and the system does not guarantee that any side effects outside your function’s inputs and outputs will persist.
This design ensures that smart functions are stateless, scalable, and predictable. If you need to maintain state (for example, counters or caches), use implementation-defined functions on the context object provided by your component.
Return values
The data your smart function returns depends on the component using it. For example:
Data Preparation expects an array of objects.
Streaming Analytics expects an array of block values.
thin-edge.io expects an array of edge messages.
Always check the documentation for your specific component to understand the expected return type.
Error handling
If your smart function throws an error, the system catches it and handles it according to component-specific policies. For example, some components may discard the input, retry the function, log the error for inspection, or raise an alarm in the tenant. You can use standard Javascript try/catch blocks to handle expected errors where you have a recovery strategy.
exportfunction onMessage(message, context) {
const deviceList = JSON.parse(new TextDecoder().decode(message.payload));
const results = [];
for (const device of deviceList) {
try {
results.push(parseMeasurementData(device.data));
} catch (error) {
console.warn(`Skipping device ${device.id}: ${error.message}`);
// Skip this device and continue with the next
}
}
return results;
}
Only catch errors when you have a meaningful recovery path. In this example, the recovery strategy is to skip the failed device but continue processing others. If there is no recovery strategy, let the error propagate — the component will handle it appropriately.
Sandbox and limits
Smart functions run in a sandboxed environment designed to protect your data, ensure platform stability, and prevent resource abuse. This section explains the security model and constraints that apply to all smart function implementations.
Sandboxing and isolation
Every smart function executes in a confined environment with strict access controls:
No filesystem access
Your smart function cannot read, write, or delete files on the host system. If your function needs to work with file-like data, you must operate on it in memory using the standard library or data passed as input.
No network socket access
Smart functions cannot open direct network connections to external services. This prevents data exfiltration and ensures that all outbound communication is controlled by the platform.
No access to other tenants’ data
If your Cumulocity instance hosts multiple tenants, each smart function runs with strict tenant isolation. Your function cannot access data, configurations, or state belonging to other tenants, even if you could guess their identifiers.
Limited system resource access
Smart functions cannot read environment variables, access the host clock in ways that compromise security, or interact with the operating system in privileged ways.
Multi-tenant and Multi-user safety
The sandboxing layer ensures that one smart function cannot interfere with any other smart functions whether deployed in other tenants or by other users. Each function runs with only the data and context explicitly passed to it.
Resource consumption limits
To prevent a single smart function from consuming all available resources and degrading the platform for others, the system enforces limits on:
CPU time
Smart functions must complete within a reasonable time window. Long-running computations or infinite loops will be terminated to prevent resource starvation. The exact timeout depends on the component and deployment configuration, but typical limits range from a few seconds to a minute per function invocation.
Memory usage
Each smart function is allocated a fixed memory budget. If your function exceeds this budget (for example, by creating very large objects or accumulating data without releasing it), execution will be terminated. The specific limit depends on your deployment and component, but you should write functions that process data efficiently without accumulating large data structures unnecessarily.
Implementations
Smart functions are available across multiple components of Cumulocity, each applying the concept to its specific domain. This page explains where smart functions are available, how they differ, and how to choose the right implementation for your use case.
Data Preparation
Deployed as: Data Preparation rule
Function name: onMessage
A Data Preparation rule contains exactly one smart function, which is applied to every inbound device message that the rule matches. The function receives a DeviceMessage and returns an array of CumulocityObject or DeviceMessage values.
Example use cases:
Parse raw device payloads and create Cumulocity measurements, events, or alarms.
Enrich messages with additional context or calculated fields.
Drop duplicate or malformed messages before they consume storage.
Route messages to different processing pipelines based on content.
A Streaming Analytics model defines a processing pipeline made up of connected blocks. Smart functions use the Smart function block to provide custom implementations within that pipeline. The function receives the output values from the preceding blocks and returns values for the next. The context provides getState() and setState() for maintaining state across invocations within a model partition.
Example use cases:
Calculate custom metrics or aggregations from real-time data streams.
Implement domain-specific anomaly detection or threshold logic.
Combine multiple data streams with custom fusion logic.
Maintain running state (for example, counters or history buffers) across events.
Function name: onMessage, onInterval and onStartup
A thin-edge.io flow defines a message-processing pipeline on the edge device and can include one or more smart functions at different stages. Each function receives a DeviceMessage and returns an array of DeviceMessage values, allowing you to filter, transform, or enrich data locally before it leaves the device.
Example use cases:
Filter or downsample high-frequency sensor data to reduce bandwidth consumption.
Perform local anomaly detection before sending data to the cloud.
Enrich device messages with local context or time-series calculations.
Route messages based on local rules before cloud transmission.
This example filters messages at the edge to reduce bandwidth:
exportfunction onMessage(message, context) {
// Only forward messages from temperature sensors
if (message.topic.includes('temperature')) {
return [message];
}
return []; // Drop other topics
}