Membrane Modulelink

This module contains functionality specific to each program.

import { state, nodes, root } from "membrane";
//                                     ↑
//                                     |
//                                     |
//                              The Membrane Module


The state object is used to keep long-lived data around.

This object is needed because every time a program is updated with new code, a new JavaScript module is created to replace the old one, but module-level variables from the old one are not automatically transferred over. The state object is thus used to share state between the two.

A good rule of thumb is to keep persistent data in the state object.


nodes is the object that holds the dependencies of a program. It holds handles to graph nodes. Using these nodes is how the program communicates with others, makes http request, etc.

Along with the dependencies that you specify, the nodes object comes with two dependencies that are injected by default:

  • nodes.process: used to read metadata about the program. For now just endpointUrl is available.
  • nodes.clock: used to read the time, set timers and cronjobs.

These two, instead of pointing to other programs on your graph, point to special system programs that can provide the corresponding functionality.

The fetch function in Membrane uses nodes.http behind the scenes to actually make requests, and sleep uses nodes.clock


root is a handle that references the program's own root node. It can be used to reference any node in the program's graph, for example to emit event, or to specify event handlers.


Field methodslink

Fields are the readable nodes in the graph.


Reads the value of a scalar field. For non-scalar fields (aka objects), use $query instead.

This method has been deprecated since you can now await a scalar field to get its value:

const value = await;

However, it's still available, so the above could be written like so:

const value = await$get();


Reads subvalues from a values by running a GraphQL query on the node. For example:

// Query two fields on a pull-request
const { title, body } = await nodes.pullRequest.$query("{ title body }");

// Outermost curly braces can be omitted.
const { title, body } = await nodes.pullRequest.$query("title body");

// Nested fields can be queried too!
const { title, comments } = await nodes.pullRequest.$query(
  "title comments { page { body } }"

Action methodslink

Actions are the callable nodes in the graph. You can think of actions as functions that can be referenced by other programs.

Actions in the UI are rendered in magenta.


Invokes the action returning a promise to its result.

This method has been deprecated since you can now await an action to invoke it:

const result = await{ ... });

However, it's still available. The above could be written with $invoke like so:

const result = await{ ... }).$invoke();


Invokes the action after the specified number of seconds.

// Invoke after a minute$invokeIn(60);


Invokes the action at the specified date.

// Invoke at the New Year$invokeAt(new Date("2023-01-01"));


Invokes the action repeatedly based on the provided cron expression. Unlike traditional cron, however, our cron expressions include seconds. For example:

// Invoke every 15 min$cron("0 */15 * * * *");

// A more elaborate example:
//               sec  min   hour   day of month   month   day of week   year
let expression = "0   30   9,12,15     1,15       May-Aug  Mon,Wed,Fri  2018/2";$cron(expression);

Event methodslink

Events are nodes you can subscribe to in order to receive notifications when they happen.

The program that exposes the event can then $emit it to invoke the handling action registered by all subscribers.

Events in the UI are rendered in purple.


Subscribes to an event. An event is always handled by an action, so you need to declare an action to handle them. We understand that it would be more convenient to allow callbacks, but callbacks are not graph-referenceable (e.g. what happens when you change the code of the callback?) but actions are, so we use them.

const id = await nodes.pullRequest.closed.$subscribe(root.handler);

// Note that the event is received in the second parameter of the action
export function handler(args, { event }) {
  console.log("The pull request has been closed", event);

// Later, to unsubscribe

Another example demonstrating how to pass arguments to the handler action. Handler args can be used to hold some context about the subscription.

const context = "hello";
nodes.some.event.$subscribe(root.handler({ context }));

// Note that the event is received in the second parameter of the action
export function handler(args, { event }) {
  console.log("Event fired", args.context, event);


Emits the event to all subscribers. For example:$emit();

The type of value passed to $emit must match the type declared in the schema. So a String-typed event could be emitted like this:$emit("Something happened");



Returns a promise that sleeps for the provided number of seconds.

await sleep(60);
console.log("After 1 minute");


Unsubscribes to a previously created subscription. For example, to subscribe for only one event:

state.subscription = await nodes.some.event.$subscribe(root.handler());

export handler() {
    console.log('Event fired. Unsubscribing');