Many modern platforms — such as AWS Lambda, Vercel, or HarperDB — allow you to run user functions as part of a serverless architecture. But in many cases, built-in runtime environments are not suitable: either a different language is needed, or special dependencies, or a specific function lifecycle.
Your own runtime is a way to fully control how user code will be executed: from loading to initialization, invocation, and termination. This architecture allows you to dynamically execute third-party functions in an isolated and secure environment.
How it works: the AWS Lambda Runtime API protocol
One of the best examples is the custom runtime from AWS. In it, your process runs inside a container, which interacts with the so-called Runtime API via HTTP.
The principle is very simple: your runtime makes a request to a special internal address /runtime/invocation/next, receives the event and call metadata, then executes the user code and sends the result back via /runtime/invocation/{requestId}/response. If an error occurs during initialization or invocation, it is sent via a special endpoint /error.
This model allows you to fully control the function execution cycle, including:
- loading and caching data in advance;
- establishing connections to external services;
- running any binary dependencies;
- passing metadata and configuring behavior.
What you need to build your runtime
The first thing is the main process, which will become the basis of the runtime.
It must:
- Get the Runtime API URL from the environment variable.
- Enter an infinite loop: request events, call the handler, send responses.
- Handle errors and termination correctly.
Such a process can be written in any language — Go, Python, Rust, even Bash. The main thing is that it can make HTTP requests and run the necessary code.
The second is the user handler itself. It can be:
- a built-in module,
- a downloadable script,
- a separate microservice,
- or even a WebAssembly module.
Your runtime must be able to call it with the necessary parameters and receive the result.
How to add an API: dynamically
Another important aspect is the ability not only to run arbitrary functions, but also to dynamically register APIs for them. For example, HarperDB offers “Custom Functions,” where you can write REST endpoints in real time that call user logic. This is implemented through a Fastify server within the runtime itself and allows you to add new routes without restarting the service.
You can build a similar model yourself: your runtime can parse the configuration file, listen to HTTP requests, and load functions and scripts that process these requests on the fly.
Extensions: monitoring, logging, security
For the runtime to be not only functional but also easy to use, you need extension points. AWS solves this through the Lambda Extensions API, a mechanism that allows you to connect additional processes or plugins that respond to init, invoke, and shutdown. This allows you to embed logging, tracing, metrics, or monitoring tools such as Datadog, New Relic, etc. into the architecture.
You can implement similar hooks in your runtime — for example, run scripts when functions start and end, or transfer data to third-party services.
Real-world examples and technologies
Among the most well-known implementations and approaches are:
- AWS Lambda Custom Runtime — an open way to create a runtime for any language, including Rust, PHP, or even COBOL.
- HarperDB Custom Functions — a built-in runtime based on Node.js/Fastify that allows you to extend the API without restarting.
- Dyninst — a tool for C/C++ that allows you to modify executable code at runtime, useful for profiling and analysis.
- WasmEdge, Wasmtime — WebAssembly engines that can be used as a secure runtime to run user code in a sandbox environment.
Conclusion
Creating your own runtime is not just an engineering task, it is an architectural decision. It allows you to:
- run arbitrary code in a controlled environment;
- isolate and safely execute user functions;
- extend the API without downtime;
- connect loggers, tracing, metrics, debugging;
- integrate functions into a scalable infrastructure.
This approach is especially relevant if you are building your own FaaS platform, creating plugins for no-code solutions, developing a low-code application editor, or a cloud IDE.