How to create a Cloud Function
A full walkthrough, from a fresh workspace to a deployed function in IXON Cloud, using a realistic example.
This guide walks you through creating a Cloud Function from scratch and getting it running both locally and in IXON Cloud. We'll build a small service logbook — two functions that let operators add and retrieve maintenance notes, stored persistently in the Document Store.
The function does not require a UI Component — we'll trigger it directly from the terminal via curl. To pair it with a UI Component, see How to visualize a Cloud Function in a UI Component after this guide.
A basic understanding of Python is assumed.
What you need
- Having completed Preparing your development environment.
- Docker Desktop — see Docker Desktop > Setup > Install. This is needed because the IXON Cloud Functions SDK, as well as the local Document Store and Object Storage instances, run in a Docker container.
- A code editor that understands Python — VS Code or PyCharm Community work well. The examples in IXON Documentation pages use VS Code.
- A user account in IXON Cloud with the Develop apps permission (for the deploy step).
1. Set up the workspace
Do not edit the MakefileThe
Makefilein the workspace is part of IXON's tooling contract. Modifying it will break local builds.
-
Download the workspace from ixoncloud/backend-component-workspace as a ZIP and extract it. (Don't clone — the workspace is intended to be checked into your own repository, and cloning IXON's directly creates Git history conflicts.)
OR
Open any terminal in the folder where you want to store your project, and use the following command to create a clean, unversioned workspace with a name of your choice:
npx degit ixoncloud/backend-component-workspace notes-manager -
Open the workspace folder in your editor.
-
Open Docker Desktop on your computer and make sure that your Docker engine is running, or you will receive an error.
-
Follow the steps found in Dev Container (recommended) to reopen the project in a Dev Container.
-
Once the project is open in a container, open a new terminal window on your editor and run
make runfrom the workspace root in your terminal.On the first run, the
Makefilecreates a Python virtual environment, installs dependencies, starts a MongoDB Docker container for the local Document Store, and starts the Ingress onhttp://127.0.0.1:8020/. It may take one or two minutes for the page to load, and in the end you'll see something like this in the terminal:CBC_PATH=./functions ./venv/bin/python3 -m ixoncdkingress 2026-04-03 11:54:24 - ixoncdkingress - INFO - Starting DocumentDB server 2026-04-03 11:54:29 - ixoncdkingress - INFO - DocumentDB server started successfully 2026-04-03 11:54:29 - ixoncdkingress - INFO - wsgiref listening on http://127.0.0.1:8020/ 2026-04-03 11:54:29 - ixoncdkingress - INFO - CBC_PATH: ./functionsLeave this terminal open — your function host runs here, and you'll see logs in this window every time the function is called.
2. Write the function
As a very first step,
Create a new file functions/logbook.py in your editor and add the following:
from datetime import datetime, timezone
from bson.json_util import dumps
import json
from ixoncdkingress.function.context import FunctionContext
@FunctionContext.expose
def add_note(context: FunctionContext, text: str) -> dict:
"""
Add a maintenance note to the logbook.
The note is tagged with the calling user's name and the current timestamp.
"""
if not context.document_db_client:
return {'success': False, 'error': 'Document Store is not available.'}
note = {
'text': text,
'author': context.user.name if context.user else 'Unknown',
'timestamp': datetime.now(timezone.utc).isoformat(),
}
context.document_db_client.insert_one(note)
return {'success': True}
@FunctionContext.expose
def get_notes(context: FunctionContext) -> list:
"""
Return the most recent logbook notes.
The number of notes returned is controlled by the `maxNotes` setting.
"""
if not context.document_db_client:
return []
limit = context.config.get('maxNotes', 50)
notes = list(context.document_db_client.find({}))
return json.loads(dumps(notes[-limit:]))Code workflow
-
The decorator
@FunctionContext.exposeis what makes a function callable from outside the workspace. Without it, the function would be unreachable. A single file can expose as many Python functions as you need. -
Both functions guard against
context.document_db_clientbeingNone— the Document Store is not guaranteed to be available in all contexts. See Document Store for details. -
context.useris populated when a real user is calling the function —add_noteuses it to automatically tag the author of each note. See Resources for details. -
context.configreads fromcontext_values.yamllocally, and from the encrypted Settings in IXON Cloud. The.get('maxNotes', 50)provides a sensible default if no limit is configured. -
bson.json_util.dumpsis needed to serialize the documents returned by the Document Store, because MongoDB assigns a BSONObjectIdas_idon insert — a type that Python's standardjsonmodule cannot handle on its own.Auto-reloadThe Ingress reloads function code on save. You don't need to restart
make runafter editinglogbook.pyorcontext_values.yaml.Do not rename the/functionsfolder!The Ingress is exposed on the
./functionsmodule by default. Renaming it breaks make run with a"No such file or directory"error. If you add a new file alongsidelogbook.pywith a different name, also create an empty__init.py__so Python treats the folder as a package.
3. Test the functions in your terminal
Open a second terminal and add a note via curl:
curl -X POST http://127.0.0.1:8020/ \
-H 'Content-Type: application/json' \
-d '{"name": "logbook.add_note", "arguments": {"text": "Replaced motor belt on conveyor line 3."}, "context": {"company": {"publicId": "1111-2222-3333-4444-5555", "name": "My Company", "custom": {}}}}'You should see a response like:
{"success": true}Now retrieve the notes you've added:
curl -X POST http://127.0.0.1:8020/ \
-H 'Content-Type: application/json' \
-d '{"name": "logbook.get_notes", "arguments": {}, "context": {"company": {"publicId": "1111-2222-3333-4444-5555", "name": "My Company", "custom": {}}}}'You should see a response like:
[{"_id": {"$oid": "..."}, "text": "Replaced motor belt on conveyor line 3.", "author": "Unknown", "timestamp": "2026-05-21T10:00:00+00:00"}]
Notes on Author and Company
- The
authorfield shows"Unknown"here because no user is set when calling viacurllocally. When a real user triggers the function from a UI Component,context.user.namewill be populated automatically. In the terminal runningmake run, you'll see an HTTP log entry for each call.- For the same reason, the
publicIdandnameof acompanymust be simulated and added to thecURLcommand.
How can I create an interface for my Cloud Function?
Now that you are done with the Cloud Function's logic, you can proceed to call it from a UI Component. For a first approach, check How to visualize a Cloud Function in a UI Component and proceed from there.
Registering, deploying and publishing your Cloud Function
Information about registration, deployment and publishing can be found in How to register, deploy and publish a Cloud Function.
Downloading a Cloud Function's logs
To inspect what happened during real calls:
- Studio > Cloud Functions > your function > More options (three dots) > Download logs.
Logs cover the current version of the Cloud Function deployed and published in the Portal, for the last 48 hours, with up to a 5-minute delay between a call and its log entry. Anything you print() or send via Python's logging module at level INFO or higher will appear in the download. Be careful not to log secrets — anyone with the Manage Apps permission can see the log file.
Sharing your Cloud Function
To share the function with another company, go to Admin > Apps and use the share option on your function. Linked UI Components are shared automatically.
What if my UI Component is linked to a Cloud Function?If the component is part of an app linked to a Cloud Function, it must be shared via the Cloud Function menu instead. In both cases, the recipient company must manually enable the app under Admin > Apps before it becomes usable.
Updated 13 days ago
