CLI tool
dannote/figma-use avatar
dannote/figma-use

figma-use: a CLI that writes to Figma over the Chrome DevTools Protocol

Control Figma from the command line. Full read/write access for AI agents — create shapes, text, components, set styles, export images. 100+ commands.

601 stars41 forksTypeScriptMIT

At a glance

What is it?
figma-use drives a running Figma desktop app from the terminal, using CLI commands or JSX, so an agent can create and modify nodes rather than only read them. The interesting part is the transport, and the constraint that follows from it.
Who is it for?
Adopt figma-use if you need an agent or a script to write into a Figma document and you accept that the target is a locally running Figma desktop app with a debugging port open. Do not adopt it if your design work lives in the browser, in Figma's cloud, or on a machine you do not control, and do not adopt it for read-only inspection, where Figma's own MCP plugin already covers the ground.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 75 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The read/write gap that figma-use fills

The README states the problem directly: Figma's official MCP plugin can read files but cannot modify them. figma-use is built for the write half. Its stated audience is AI agents, and the design argument is that models already know two things well, command line tools and React, so the interface borrows both. Commands stay short because an agent generating dozens of operations pays for every token, and JSX is used as the description format because a layout expressed as nested `Frame` and `Text` elements needs no schema to explain. If you are a human who wants to script Figma, the same interface applies. If you want an agent to build a screen, a component set, or a set of design tokens inside an open document, that is the target use.

Remote debugging is the transport, and the 126 problem

There is no plugin to install. figma-use attaches to the Figma desktop app through the Chrome DevTools Protocol, which means Figma has to be started with a debugging port open. The README gives the invocation per platform: `open -a Figma --args --remote-debugging-port=9222` on macOS, the equivalent path under `%LOCALAPPDATA%` on Windows, and `figma --remote-debugging-port=9222` on Linux. Connection is then confirmed with `figma-use status`. The README's own warning at the top says Figma 126 and later blocks remote debugging, and that figma-use still works through `figma-use daemon start --pipe`. Release v0.13.5 added custom CDP port support, v0.13.4 addressed rspack support for Figma 126.6 and later, and v0.13.3 was a bootstrap fix for Figma 126. Three releases in the 0.13 line all touching the same surface tells you where the maintenance pressure sits: the connection layer tracks a closed-source application's internals, and each Figma release can move it. That is the structural cost of this approach, not a bug to be fixed once.

Two authoring modes: one command at a time, or a JSX tree

The imperative mode is a single command per change. The README's first example creates a frame with `figma-use create frame --width 400 --height 300 --fill "#FFF" --layout VERTICAL --gap 16`, and layout can be changed afterwards with `figma-use set layout 1:23 --mode GRID --cols "1fr 1fr 1fr" --gap 16`. The declarative mode pipes JSX into `figma-use render --stdin --x 100 --y 100`, and the README is explicit that stdin accepts pure JSX only, with no variables and no logic. Anything with components, variants, or conditions belongs in a `.figma.tsx` file instead. The element set is listed as `Frame`, `Rectangle`, `Ellipse`, `Text`, `Line`, `Star`, `Polygon`, `Vector`, `Group`, `Icon`, and `Image`. The style object is not CSS: keys such as `p`, `gap`, `flex: "col"`, `bg`, and `rounded` are shorthand, and grid is expressed with `display: 'grid'` plus `cols` and `rows` accepting `px`, `fr`, and `auto` or `hug`, with `colGap` and `rowGap` for separate axes. Treat the style vocabulary as its own dialect and read the examples rather than assuming CSS behaviour.

Components, variants, and variables as first-class output

The part worth attention is that the JSX layer maps onto real Figma constructs rather than just drawing shapes. `defineComponent` creates a master on first call and instances thereafter, so three `<Card />` elements produce one component and two instances. `defineComponentSet` takes a name, a record of variant axes, and a render function, and the README states it creates a real ComponentSet with all combinations, not four separate buttons. `defineVars` binds colours to Figma variables by name, with the hex value serving as a fallback when the variable is not present. That fallback behaviour is a design decision worth noting: a render against a file without the matching variable will still produce output, so a missing token shows up as a hardcoded colour rather than an error. If your workflow depends on tokens being bound, check the result in Figma rather than trusting that the render succeeded.

Icons, images, and export back to JSX

Icons come from Iconify by name, with no download or import step: `figma-use create icon mdi:home` or `figma-use create icon lucide:star --size 48 --color "#F59E0B"`, and the same via `<Icon icon="mdi:home" size={24} color="#3B82F6" />`. The README points to icon-sets.iconify.design for browsing. Images load from a URL with `<Image src="..." w={200} h={150} />`. The reverse direction is `figma-use export jsx 123:456 --pretty`, which emits a function component importing from `figma-use/render`. There is an optional path for matching vector shapes back to Iconify icons: install `whaticon` and pass `--match-icons --prefer-icons lucide`. Two nodes can be compared as a JSX diff with `figma-use diff jsx 123:456 789:012`, and components can be emitted as Storybook stories with `figma-use export storybook --out ./stories`, which the README labels experimental. The round trip is the most reusable idea here: a node becomes JSX, the JSX becomes a file, and the file can be rendered again elsewhere.

What breaks, and when this is the wrong tool

The dependency chain is the main limitation. figma-use needs the Figma desktop app running locally with remote debugging enabled, and Figma 126 and later blocks that path, which is why the pipe-based daemon exists. A headless CI runner, a container, or a browser-only Figma session is outside the design. The README also promotes an alternative for exactly that reason, pointing to OpenPencil as an open-source editor that reads and writes .fig files, which sidesteps Figma entirely. Beyond connectivity, the stdin renderer's no-variables rule means any real templating has to move to `.figma.tsx` files. The Storybook export is marked experimental, so treat it as a draft path rather than a build step. And because the tool writes directly into a live document, an agent with a wrong coordinate or a wrong node id is editing your working file, not a copy. The README does not describe an undo, dry-run, or sandbox mode, so plan the target document accordingly.

The alternative, and the difference in approach

Figma's official MCP plugin reads files but cannot modify them, per the README. That is a clean split: if your task is inspection, summarising, or extracting structure, the official plugin is the safer route because it does not require a debugging port and does not depend on Figma's internals. figma-use exists for the write case, and it pays for that by attaching to a running desktop application over CDP. OpenPencil is a different trade again: an open-source editor that reads and writes .fig files, with built-in AI and P2P collaboration. Choosing it means leaving Figma as the runtime, which removes the version-tracking problem but also removes the thing most teams are actually trying to automate. So the decision is not which tool is better. It is whether the write target must be Figma, and whether a local desktop process with a debugging port is acceptable in your environment.

Licence, maintenance, and upgrade cost

The repository is MIT licensed, which permits commercial use and modification, but this is not legal advice and you should read the licence text yourself before relying on it. Maintenance cost is visible in the release cadence: v0.13.3, v0.13.4, and v0.13.5 landed between April and July 2026, and all three concern compatibility with Figma internals or the connection layer. Budget for the possibility that a Figma update breaks the link before figma-use catches up, and keep the daemon pipe flag in mind as the fallback. The project is published on npm and can be run without installing globally via `npx figma-use status`, which makes it cheap to evaluate. What you cannot get from the README alone is a picture of how the 100+ commands are documented individually, or how stable the JSX style vocabulary is across versions. Those are the things to check against your own use case before wiring an agent to it.

Editorial conclusion

Adopt figma-use if you need an agent or a script to write into a Figma document and you accept that the target is a locally running Figma desktop app with a debugging port open. Do not adopt it if your design work lives in the browser, in Figma's cloud, or on a machine you do not control, and do not adopt it for read-only inspection, where Figma's own MCP plugin already covers the ground. Before committing, verify two things on your own machine: that `figma-use status` reports a connection under your Figma version, and whether you need `figma-use daemon start --pipe` because of the Figma 126 change.

Official sources

  1. dannote/figma-use on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes