A powerful new way to quickly build internal tools, automations, admin panels, and much more.

LAUNCH

Simplify persistance

There's no need to connect a database (although you can!) because Membrane programs run in a durable JavaScript runtime.

That's right, we transparently persist memory changes so that you don't worry about loading and storing state.

Any JavaScript object can persist indefinitely because Membrane's execution timeout is effectively

Keep long-lived values in state.
import { state } from "membrane";
state.notes = state.notes ?? []
export async function saveNote({ args }) {
  state.notes.push(args.note);
}

Auditable

The most time-consuming part of bugfixing can often be reproducing the issue in the first place. We didn't like that, so we fixed it!

In Membrane, every side-effect is first written to the program's write-ahead log and then processed. HTTP requests and responses, source code changes, queries, etc are all program side-effects.

This log gives you clear understanding plus the ability to replay history so that reproducing bugs is a walk in the park.

Membrane logs are not just text output; they are the source of truth!

The Graph

In Membrane, each program defines a graph API to expose its data and functionality to other programs. You can think of the graph as objects that can be referenced by other programs, allowing you to easily compose functionality.

In this video we showcase the graph in a quick tour of the Membrane IDE.

Showcase
FEATURES
EXAMPLES
example weekly report
Example of a Membrane program to generate a weekly report on issues, pull requests, and commits in a GitHub organization
Set up a cron-job that generates report every Friday.
New Google Doc
Find Issues & Pull Requests
Append Issue & PR Details
Search & Select Commits
Append details of commits
import { root, nodes, state } from "membrane";

export async function configure({ org }) {
  state.org = org;
  root.report.$cron(`0 0 17 ? * FRI`);
}

export async function report() {
  const [weekAgo, now] = getDateRangeString();
  const { org } = state;

  const doc = await nodes.gdocs.documents.create({
    title: `Last Week Report - ${now}`,
  });

  await doc.insertText({
    text: `Weekly Report (${weekAgo} to ${now})`,
  });

  const issuesAndPr = await nodes.github.search
    .issues({ q: `org:${org}+created:${weekAgo}..${now}` })
    .$query(`{ items { html_url title created_at user {login}}}`);

  await doc.insertText({ text: `Issues and Pull Requests:` });
  for (let event of issuesAndPr.items!) {
    await doc.insertText({
      text: `${event.user!.login}: ${event.created_at!}`
    });
    await doc.insertLink({
      text: `${event.title}`, url: event.html_url
    });
  }

  const commits = await nodes.github.search
    .commits({ q: `org:${org}+committer-date:${weekAgo}..${now}` })
    .$query(`{ items { sha html_url message date author {login}}}`);

  await doc.insertText({ text: `Commits Summary:` });
  for (let event of commits.items!) {
    await doc.insertBullet({
      text: `${event.author!.login}: ${event.date!} - ` });

    await doc.insertLink({
      text: `${event.message!.replace(/g, "")}`,
      url: event.html_url
    });
  }

  const url = await doc.url;
  console.log(`Report generated at ${url}`);
}
Capabilities
FEATURES
EXAMPLES
Example of a Membrane program to generate a weekly report on issues, pull requests, and commits in a GitHub organization
Set up a cron-job that generates report every Friday.
New Google Doc
Find Issues & Pull Requests
Append Issue & PR Details
Search & Select Commits
Append details of commits
import { root, nodes, state } from "membrane";

export async function configure({ org }) {
  state.org = org;
  root.report.$cron(`0 0 17 ? * FRI`);
}

export async function report() {
  const [weekAgo, now] = getDateRangeString();
  const { org } = state;

  const doc = await nodes.gdocs.documents.create({
    title: `Last Week Report - ${now}`,
  });

  await doc.insertText({
    text: `Weekly Report (${weekAgo} to ${now})`,
  });

  const issuesAndPr = await nodes.github.search
    .issues({ q: `org:${org}+created:${weekAgo}..${now}` })
    .$query(`{ items { html_url title created_at user {login}}}`);

  await doc.insertText({ text: `Issues and Pull Requests:` });
  for (let event of issuesAndPr.items!) {
    await doc.insertText({
      text: `${event.user!.login}: ${event.created_at!}`
    });
    await doc.insertLink({
      text: `${event.title}`, url: event.html_url
    });
  }

  const commits = await nodes.github.search
    .commits({ q: `org:${org}+committer-date:${weekAgo}..${now}` })
    .$query(`{ items { sha html_url message date author {login}}}`);

  await doc.insertText({ text: `Commits Summary:` });
  for (let event of commits.items!) {
    await doc.insertBullet({
      text: `${event.author!.login}: ${event.date!} - ` });

    await doc.insertLink({
      text: `${event.message!.replace(/g, "")}`,
      url: event.html_url
    });
  }

  const url = await doc.url;
  console.log(`Report generated at ${url}`);
}
The Write-Ahead Blog

If you're curious about Membrane's architecture, Juan joined the devtools.fm podcast to talk through the nuts and bolts.



Enter your email for occasional updates