Skip to main content

Introducing figma-await-ipc: A simple await-able replacement for postMessage() cross-thread communication

  • September 13, 2023
  • 3 replies
  • 1032 views

FWExtensions

In a Figma plugin, the code that has access to the document API and the code that renders the UI are in different contexts, so you need to use postMessage() to send a request for data from one thread to the other. The other thread then needs to listen for the "message" event and respond by calling postMessage() to send back the requested data. The source thread then also needs to listen for the "message" event to receive the requested data.

All of this asynchronous event handling is an awkward fit for what is conceptually a synchronous function call. The figma-await-ipc package wraps this process with a simpler interface.

The package’s call() function lets you essentially call a named function in the other thread, while awaiting the promised result. Any parameters you pass to call() after the function name will be passed into the receiving function:

// main.ts
import { call } from "figma-await-ipc";

try {
  const title = await call("getProperty", "title");
  figma.currentPage.selection[0].characters = title;
} catch (error) {
  console.error("Error fetching name property:", error);
}

Of course, making a call from one thread won’t do anything if there’s nothing in the other thread to receive that call. So every call() to a particular name must be paired with a receive() in the other thread to provide a function that will respond to that name:

// ui.tsx
import { receive } from "figma-await-ipc";

const storedProperties = { ... };

receive("getProperty", (key) => {
  if (!(key in storedProperties)) {
    throw new Error(`Unsupported property: ${key}`);
  }

  return storedProperties[key];
});

Any number of call()/receive() pairs can exist within a plugin, and they can make calls in either direction: from the main thread to the UI thread, or vice versa.

Let me know if anyone has questions about the figma-await-ipc package, or suggestions for improvements. There’s more info in the readme as well.

3 replies

FWExtensions
  • Author
  • November 18, 2023

I changed the package name to figma-await-ipc, which I hope is a little clearer on what it’s for (at least if you know what IPC means). The latest package is available here:

GitHub

I originally created this functionality for the fwidgets UI toolkit that I recently published.


Gleb
  • Power Member
  • November 19, 2023

Epic stuff! Thanks for sharing!


Jakub Hajduk
  • New Member
  • November 12, 2025

Hi ​@FWExtensions

Thanks for your work. I really liked your idea of awaitable messaging system. It helped me with some of my plugins.

It also inspired me to write my own lib with type inference between ui and main code and rejects support. It’s called figwire

On the plugin side:

import { defineApi } from 'figwire/plugin';

const pluginApi = defineApi({
greet: (name: string) => `Hello ${name}!`
});

export type PluginAPI = typeof pluginApi;

And then on the UI side:

import { client } from 'figwire/ui';
import type { PluginAPI } from './plugin';

(async () => {
const pluginApiClient = client<PluginAPI>();
const greeting = await pluginApiClient.greet('Johnny Jeep');

console.log(greeting); // "Hello Johnny Jeep!"
})();


Hope you don’t mind me posting this link here - https://www.npmjs.com/package/figwire.