Platform
Edge Export
Kemu Edge Export
Table of Contents
- Edge Export
- Export Modes: Javascript Library vs Shell Script
- Export Process
- Folder Structure
- Using the Exported Recipe
- SDK Helper Methods
- Integration Examples
- Deployment Considerations
Edge Export
Edge Export converts Kemu recipes into standalone Node.js applications that run independently of the Kemu platform. This enables:
- Independent deployment: Run recipes on any server, cloud platform, or local machine
- System integration: Embed recipe functionality into existing applications
- Scalable architecture: Deploy multiple instances without platform dependencies
- Note: Internet connection is required for Edge recipes to function unless you are on an enterprise plan.
The export process transforms visual recipe workflows into executable code while preserving all logic, connections, and custom functionality.
Export Modes: Javascript Library vs Shell Script
Kemu Edge Export supports two export modes optimized for different use cases:
Javascript Library Mode
- Purpose: Creates a
Node.jsapplication for programmatic integration into existing projects - Execution: Run with
node main.jsor import as a module - Best For: Development environments, microservices, and applications requiring programmatic control
Shell Script Mode
- Purpose: Creates a standalone executable with convenient startup scripts
- Execution: Double-click
start.bat(Windows) orstart.sh(Linux/macOS) - Best For: Standalone deployment, non-technical users, and production environments
Key Difference: Shell Script mode includes startup scripts for easy execution, while both modes share identical core files and dependencies.
Export Process
UI Export Steps
To export a recipe from the Kemu UI:
- Click the Home icon (house) in the Kemu interface
- Select "Kemu Edge Export" from the available options
- Optionally rename the export folder (defaults to recipe name)
- Click the folder icon to choose the save location
- Select the export mode (
Javascript LibraryorShell Script) - Click "Export" and wait for completion
The export process creates a complete, self-contained application package with all necessary dependencies and runtime components.

Folder Structure
An export package contains:
Recipe Name/ ├── main.js # Main entry point for the recipe ├── package.json # Node.js dependencies and configuration ├── package-lock.json # Dependency lock file ├── recipe.kemu # Recipe definition and configuration ├── .env # Environment variables and secrets └── node_modules/ # Installed dependencies
Additional files (depending on export mode):
Shell Script Mode:
├── start.bat # Windows startup script └── start.sh # Linux/macOS startup script
With Custom Services:
└── services/ # Kemu services used by the recipe └── service-name@version/ ├── dist/ # Compiled service code │ ├── processor.js # Main service processor │ ├── manifest.json # Service metadata │ ├── variants/ # Service variants │ └── lib/ # Service libraries └── package.json # Service-specific dependencies
Key Files:
main.js: Entry point that starts the recipe using Edge Runtimepackage.json: Defines the project as a Workspace Configuration with Edge Runtime dependencyrecipe.kemu: Complete recipe definition including widgets, connections, and custom logic.env: Contains environment variables and all configured secrets for the recipeservices/: All Kemu service used by the recipe with compiled code and dependenciesstart.bat/start.sh: Convenience scripts for Shell Script mode execution
Using the Exported Recipe
Basic Execution
Javascript Library Mode
- Install dependencies:
npm install - Start the recipe:
node main.js
Shell Script Mode
- Install dependencies:
npm install - Start the recipe:
- Windows:
start.batornode main.js - Linux/macOS:
./start.shornode main.js
- Windows:
SDK Helper Methods
The Kemu Edge SDK provides comprehensive helper methods for working with recipes:
Available Methods
- start() - Initialize and start the Kemu Edge Runtime
- terminate() - Gracefully shut down the recipe runtime
- sendToInputWidget() - Send data to input widgets in your recipe
- sendToInputWidgetAndWaitForOutput() - Send data to input widgets and wait for output widget response
- globalVariables - Manage global variables in your recipe
- status - Monitor status values set by Status widgets
- edgeFunctions - Register and manage edge function handlers
- utils.loadImageFile() - Load images from various sources
- utils.encodeImageData() - Encode image data to different formats such as
"png","jpeg", or"webp"
Basic Recipe Interaction
The default main.js file contains:
import kemuEdge from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); await kemuEdge.start(); console.log('Recipe running...'); // To Send data to input widgets /* import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); await recipe.sendToInputWidget('INPUT_NAME', { type: DataType.Number, value: 123 }); */
The start method initializes the Edge Runtime and begins executing your recipe. It returns a Recipe Instance that provides methods for interacting with your recipe.
The commented section provides an example about how to interact with the exported recipe by sending data to an Input Widget.
Terminating the Recipe
The terminate method allows you to gracefully shut down the Edge Runtime and stop all recipe processing.
import kemuEdge from '@kemu-io/edge-runtime'; // Start the recipe await kemuEdge.start(); console.log('Recipe running...'); // ... your application logic ... // Terminate the recipe when done await kemuEdge.terminate(); console.log('Recipe terminated');
Note: The terminate method is asynchronous and should be awaited to ensure proper cleanup before your application exits.
Data Types
import { DataType } from '@kemu-io/edge-runtime'; // Available data types DataType.Number // Numeric data (integer or floating point) DataType.String // Text data DataType.ArrayBuffer // Raw binary data buffer DataType.Array // Array of items DataType.Boolean // True/false values DataType.JsonObj // JavaScript object (JSON-compatible) DataType.Anything // Accepts any data type (used by actions that don't care about the value) DataType.ImageData // Raw image data (produced in browser environments) DataType.AudioBuffer // Raw audio data buffer DataType.Rect // Rectangle with width, height, top, left properties DataType.Point // Point with x, y coordinates DataType.ImageBitmap // Image bitmap data DataType.BinaryFile // Custom binary data with format specification (e.g., `'image/png'`, `'audio/mp3'`)
Sending Data to Input Widgets
Input Widgets serve as the entry points for external data into your Kemu recipe. They act as receivers that accept data from your application code and pass it into the recipe workflow. This is the primary way to:
- Trigger recipe execution: Send data to start or continue recipe processing
- Provide external inputs: Feed data from your application into the recipe
- Control recipe flow: Use different input widgets to handle different types of data
- Integrate with external systems: Connect your application logic with Kemu recipe workflows
Important: Input Widgets must be configured in your recipe with specific names and data types. Your code must send data that exactly matches these configurations for successful communication.
Requirements:
- Name Match: The Input Widget name in your recipe must exactly match the name passed to
sendToInputWidget() - Data Type Match: The Input Widget's configured data type must match the
DataTypeused in your code (see Data Type Mapping)
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Send string data (Input Widget must be named "greeting" and configured as "String" type) await recipe.sendToInputWidget('greeting', { type: DataType.String, value: 'Hello World!' }); // Send image data (Input Widget must be named "process-image" and configured as "Image" type) await recipe.sendToInputWidget('process-image', { type: DataType.ImageData, value: imageData }); // Send JSON object (Input Widget must be named "userData" and configured as "Object" type) await recipe.sendToInputWidget('userData', { type: DataType.JsonObj, value: { id: 1, name: 'John Doe', email: 'john@example.com' } });
Common mistakes:
- Code calls
'process-image'but Input Widget is named'image'→ Will fail - Code uses
DataType.ImageDatabut Input Widget is configured as"String"type → Will fail
Error Example: If you send the wrong data type, you'll see an error like:
Invalid data type: 0 for input: name. Expected: 1
This means the Input Widget expects a String (type 1) but a Number (type 0) was sent.
Sending Data and Waiting for Output
The sendToInputWidgetAndWaitForOutput method allows you to send data to an input widget and wait for the response from an output widget in the execution path. This is ideal for synchronous workflows where you need to wait for the recipe to complete processing before continuing.
This method is useful for:
- Synchronous operations: Wait for recipe processing to complete before proceeding
- Direct result retrieval: Get the output value directly without setting up listeners
- Simplified code flow: Use async/await pattern instead of event listeners
- API integrations: Return processed results directly in API responses
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Send data and wait for the output widget response const result = await recipe.sendToInputWidgetAndWaitForOutput('process-data', { type: DataType.String, value: 'Hello World' }); console.log('Recipe result:', result); // The result contains the value sent to the output widget in the execution path
Important: This method requires an Output Widget in the execution path from the input widget. If no output widget is reached, the promise will hang indefinitely.
Global Variables Management
Global variables allow you to share data across your recipe and interact with it from external code. The global variables API provides methods to monitor, set, retrieve, and manage variables programmatically.
Available Methods:
onChange(varName, callback)- Listen for changes to a specific global variableonChange('*', callback)- Listen for changes to all global variablessetValue(varName, value, config?)- Set the value of a global variablegetValue(varName)- Get the current value of a global variablegetAll()- Get all global variablesdelete(varName)- Remove a global variable
Listening for Variable Changes:
import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Listen for changes to a specific variable recipe.globalVariables.onChange('output-image', (variable) => { console.log('Output image updated:', variable.lastValue); console.log('Variable name:', variable.name); console.log('Previous value:', variable.previousValue); }); // Listen for changes to all variables recipe.globalVariables.onChange('*', (variable) => { console.log('Any variable changed:', variable.name, variable.lastValue); }); // Send data to trigger variable updates await recipe.sendToInputWidget('process-image', imageData);
Setting and Getting Variables:
import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Set a global variable value await recipe.globalVariables.setValue('savePath', '/path/to/output.png'); // Set with options to control notifications await recipe.globalVariables.setValue('config', { quality: 90, format: 'jpeg' }, { disableChangeNotifications: false, // Don't trigger change listeners disableDefineNotifications: false, // Don't trigger define listeners doNotOverrideExisting: false // Allow overwriting existing values }); // Get a specific variable const savePath = recipe.globalVariables.getValue('savePath'); console.log('Save path:', savePath?.lastValue); // Get all variables const allVariables = recipe.globalVariables.getAll(); console.log('All variables:', allVariables); // Delete a variable recipe.globalVariables.delete('savePath');
Unsubscribing from Changes:
The onChange method returns an unsubscribe function for cleanup:
const unsubscribe = recipe.globalVariables.onChange('output-image', (variable) => { console.log('Image updated:', variable.lastValue); // Stop listening after first update if (variable.lastValue) { unsubscribe(); } });
Status Monitoring
Status widgets allow your recipe to communicate status updates that can be monitored from external code. This is useful for tracking progress, errors, or state changes in your recipe workflows.
Listening for Status Changes:
import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Listen for any status value changes recipe.status.onChange((status) => { console.log('Status changed:', status.name); console.log('Status value:', status.value); console.log('Source widget:', status.sourceWidget); console.log('Status widget ID:', status.statusWidgetId); }); // Send data that triggers status updates await recipe.sendToInputWidget('setStatus', 'processing');
Unsubscribing from Status Changes:
const unsubscribe = recipe.status.onChange((status) => { console.log('Status:', status); // Stop listening after specific condition if (status.value.type === DataType.String && status.value.value === 'complete') { unsubscribe(); } });
Edge Functions
Edge functions allow you to register custom JavaScript handlers that can be called from within your recipe. This enables powerful customization where your recipe can invoke external code functions dynamically.
Registering a Function Handler:
import kemuEdge from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Register a handler for an edge function recipe.edgeFunctions.register('do-something', async (event) => { console.log('Edge function called with:', event); // Perform custom logic const result = await performCustomOperation(event.data); // Return the result return result; }); // When the recipe calls the 'do-something' edge function, // your handler will be invoked with the event data. // You recipe will wait for the result of the function and send it to its output port.
Unregistering a Function Handler:
// Remove a specific handler recipe.edgeFunctions.unregister('do-something'); // Clear all registered handlers recipe.edgeFunctions.clearAll();
Image Processing and Loading
Loading Images from Different Sources
import kemuEdge, { utils, DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); // Load image from URL const image = await utils.loadImageFile('https://example.com/image.jpg'); // Load image from local file const localImage = await utils.loadImageFile('./path/to/image.jpg'); // Load image from Base64 string const base64String = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD...'; const imageFromBase64 = await utils.loadImageFile(base64String);
Integration Examples
Basic String Input with Asynchronous Output
This example demonstrates how to use an Input Widget as the entry point by using the sendToInputWidget asynchronous method, and receiving the result by monitoring global variable changes:
Drag the example onto the workspace to explore and experiment!
In this example:
- Input Widget (
greeting) receives the string"Hello World!"from the external code - Text Widget processes the input and generates a response
"Hi there!" - Variable Widget (
greeting-response) stores the response as a global variable - External Code receives the response through the global variable change listener and logs it to the console
Flow Summary: External Code → Input Widget → Text Widget → Global Variable → External Code Listener
How to Run This Example
- Export the recipe as "Javascript Library Mode" from Kemu Edge
- After exporting as a JavaScript library, open the exported project in your code editor (e.g., VS Code). The
main.jsfile contains an example of how to start the recipe and send data to input widgets. By default, it looks like this:
import kemuEdge from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); await kemuEdge.start(); console.log('Recipe running...'); // To Send data to input widgets /* import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; const recipe = await kemuEdge.start(); await recipe.sendToInputWidget('greeting', { type: DataType.Number, value: 123 }); */
- Replace the existing code with the code below (to simulate input after export)
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); const recipe = await kemuEdge.start(); console.log('Recipe running...'); // Set up listener for the response variable recipe.globalVariables.onChange('greeting-response', (variable) => { console.log('Received response:', variable.lastValue); console.log('Variable name:', variable.name); console.log('Previous value:', variable.previousValue); }); // Send data to the input named "greeting" await recipe.sendToInputWidget('greeting', { type: DataType.String, value: 'Hello World!' }); console.log('Greeting sent, waiting for response...');
- Open the exported folder in terminal and run:
npm install node main.js
Note: If you enabled "Install dependencies" during export,
npm installwas already executed automatically. Key changes: Uncomment the example code, changeDataType.NumbertoDataType.String, add the response listener, and modify the input value.
-
Expected Output: The terminal will display:
Starting recipe... Recipe running... Greeting sent, waiting for response... Received response: Hi there! Variable name: greeting-response Previous value:The recipe processes the input string "Hello World!" and returns the greeting response "Hi there!" through the Variable Widget, which triggers the global variable change listener.
Basic String Input with Synchronous Output
This example demonstrates how to use an Input Widget as the entry point by using the sendToInputWidgetAndWaitForOutput synchronous method, and awaiting for the result provided by the Output Widget:
Drag the example onto the workspace to explore and experiment!
In this example:
- Input Widget (
greeting) receives string data from external code viasendToInputWidgetAndWaitForOutput() - Text Widget processes the input and generates a greeting response:
"Hi there!" - Output Widget transmits the final processed result directly back to external code
How to Run This Example
- Export the recipe as
"Javascript Library Mode"from Kemu Edge - Open the exported folder in your favorite code editor and modify the
main.jsfile with the following code:
import kemuEdge, { DataType } from '@kemu-io/edge-runtime'; console.log('Starting recipe...'); const recipe = await kemuEdge.start(); console.log('Recipe running...'); // Send data and wait for output directly const result = await recipe.sendToInputWidgetAndWaitForOutput('greeting', { type: DataType.String, value: 'Hello World' }); console.log('Recipe result:', result);
-
Open the terminal and run:
npm install node main.jsNote: If you enabled "Install dependencies" during export,
npm installwas already executed automatically. -
Expected Output: The terminal will display:
Starting recipe... Recipe running... Recipe result: Hi there!The recipe processes the input string "Hello World" and returns the greeting response "Hi there!" directly through the Output Widget.
Image Processing Integration
This example demonstrates a complete image processing workflow with file saving. The utils.encodeImageData method converts raw ImageData objects into common image file formats:
Drag the example onto the workspace to explore and experiment!
In this example:
- Input Widget (
process-image) receives image data from external code viasendToInputWidget() - Image Filter Widget applies grayscale filter to the received image
- Image Resize Widget resizes the filtered image to
100x100pixels - Variable Widget (
image-processed) stores the processed result as a global variable - External Code receives the processed image through the global variable change listener and saves it as a
JPEGfile
How to Run This Example
- Export the recipe as
"Javascript Library Mode"from Kemu Edge - Open the exported folder in your favorite code editor and modify the
main.jsfile with the following code:
import path from 'path'; import fs from 'fs'; // NOTE: contains helper functions to manipulate images import kemuEdge, { utils, DataType } from '@kemu-io/edge-runtime'; // Start recipe const recipe = await kemuEdge.start(); // Load image from URL const image = await utils.loadImageFile('https://cdn.pixabay.com/photo/2012/01/09/09/10/sun-11582_1280.jpg'); console.log('Image loaded'); // Create a listener for when the image is processed recipe.globalVariables.onChange('image-processed', async (variable) => { try { const image = variable.lastValue; const targetPath = path.resolve('./image-processed.jpeg'); console.log(`Image processed, saving file to "${targetPath}"`); const jpgBuffer = await utils.encodeImageData(image, 'jpeg'); fs.writeFileSync(targetPath, jpgBuffer); process.exit(0); } catch(error) { console.error('Error saving image', error); process.exit(1); } }); // Send image to input widget await recipe.sendToInputWidget('process-image', { type: DataType.ImageData, value: image });
Note, some important code in the modify file:
utils.loadImageFile(url): Loads an image from a URL or file path and returns it as ImageData, which can be sent to the input widgetrecipe.globalVariables.onChange('image-processed', async (variable) => { ... }): Listens for changes to theimage-processedglobal variable, so you can react when the image processing is complete and save the result
-
Open the terminal and run:
npm install node main.jsNote: If you enabled "Install dependencies" during export,
npm installwas already executed automatically. -
Expected Output: The terminal will display:
Image loaded Image processed, saving file to "/path/to/your/exported/folder/image-processed.jpeg"The recipe processes the image from the URL, applies grayscale filter and resizes it to
100x100pixels, then saves the result asimage-processed.jpegin the exported folder.
Express.js Integration
This example demonstrates how to integrate an Express server with a Kemu recipe by sending an API request with an imageUrl, which the recipe processes and returns as a Base64 string in the response:
Drag the example onto the workspace to explore and experiment!
In this example:
- Input Widget (
process-image) receivesImageDatafrom external code viasendToInputWidgetAndWaitForOutput() - Image Filter Widget applies grayscale filter to the received image
- Image Resize Widget resizes the filtered image to
100x100pixels - Output Widget transmits the processed image directly back to external code
- External Code receives the processed image and converts it to
Base64for theAPIresponse
How to Run This Example
- Export the recipe as
"Javascript Library Mode"from Kemu Edge - Open the exported folder in your favorite code editor and modify the
main.jsfile with the following code:
import express from 'express'; import kemuEdge, { utils, DataType } from '@kemu-io/edge-runtime'; const app = express(); app.use(express.json()); // Route that triggers the recipe app.post('/api/process-image', async (req, res) => { const { imageUrl } = req.body; const image = await utils.loadImageFile(imageUrl); console.log('Starting recipe...'); const recipe = await kemuEdge.start(); // Send image to input widget const result = await recipe.sendToInputWidgetAndWaitForOutput('process-image', { type: DataType.ImageData, value: image }); const jpgBuffer = await utils.encodeImageData(result, 'jpeg'); res.json({ success: true, image: `data:image/jpeg;base64,${jpgBuffer.toString('base64')}` }); }); // Start the server app.listen(3000, () => console.log('Server running on port 3000'));
-
Open the terminal and run:
npm install express node main.jsNote: If you enabled "Install dependencies" during export,
npm installwas already executed automatically. -
Test the API using Postman:
- Method: POST
- URL:
http://localhost:3000/api/process-image - Headers:
Content-Type: application/json - Body (raw JSON):
{ "imageUrl": "https://cdn.pixabay.com/photo/2012/01/09/09/10/sun-11582_1280.jpg" }
-
Expected Output:
- Terminal: The server will display:
Server running on port 3000 - Postman Response: The API will return a JSON response:
{ "success": true, "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..." }
The recipe processes the image from the URL, applies grayscale filter and resizes it to
100x100pixels, then returns the processed image as aBase64string in theAPIresponse. - Terminal: The server will display:
Deployment Considerations
System Requirements
- Node.js: Version
22.2.0or higher required - Platform Support: Windows, macOS, and Linux (multiple architectures)
- Memory: Adequate
RAMfor image processing workflows - Storage: Space for dependencies and temporary files
Best Practices
- Testing: Test exported recipes in target environment before deployment
- Error Handling: Implement proper error handling in custom logic
- Resource Monitoring: Monitor
CPUand memory usage for independent Recipe Instances - Process Management: Use process managers like
PM2for production deployments - Security: Consider security implications when exposing webhooks publicly
Performance Considerations
- Image Processing: Large images may require significant
memoryallocation - Concurrent Requests: Monitor resource usage under high load
- Service Initialization: Allow adequate startup time for Service Dependencies initialization
Glossary
-
Edge Runtime
The standalone execution environment that runs exported Kemu recipes independently of the Kemu platform. It provides the necessary APIs and utilities for interacting with recipes programmatically.
-
Recipe Instance
The object returned by
kemuEdge.start()that provides methods for sending data to input widgets and managing recipe execution. Each recipe instance represents a running copy of your exported recipe. -
Event Listener
A callback function that responds to specific events in the recipe, such as variable changes or widget outputs. Listeners allow external code to react to recipe state changes in real-time.
-
Data Type Mapping
The correspondence between Kemu Edge data types (like
DataType.String,DataType.Number) and the data types configured in your recipe widgets. Proper mapping is essential for successful data transmission. -
Recipe State
The current values and configuration of all widgets in a running recipe. The state persists during recipe execution and can be monitored through variable change listeners.
-
Export Package
The complete set of files generated when exporting a recipe, including the recipe definition, dependencies, runtime components, and any custom services used by the recipe.
-
Service Dependencies
Additional Kemu services (like custom widgets or external integrations) that your recipe requires to function. These are automatically included in the export package when present.
-
Workspace Configuration
The
package.jsonfile in exported recipes that defines the project as a workspace with Kemu Edge Runtime as a dependency, enabling proper module resolution and execution. -
Process Management
The handling of recipe lifecycle events like startup, execution, and termination. Proper process management ensures clean resource cleanup and prevents memory leaks in long-running applications.