Docs menu · CLI reference
Language English

CLI reference

Command Output
tree <file> [node] [--depth N] [--json] Node ids, REST types (as in nodes) and names; indented text, or nested JSON with each node's size, hidden flag and auto-layout mode, plus firstText (first visible text) on nodes of a page or section
tree <file> [node] --top-frames [--json] Only the screens, one per line, ready for --frames -: frames, components, component sets and instances on a page or in its sections (groups and internal pages skipped); --json adds page and section ids and each screen's first visible text (firstText), which tells canvas labels from screens
find <file> <query> [--type TYPE] [--node ID] [--limit N] Case-insensitive search over layer names and text; paths, sizes and previews. Default 20 results (1-200)
search <file> <query> [--node ID] [--type T[,T]] [--limit N] [--cursor C] [--include-hidden] [--include-internal] [--mode text|semantic|hybrid|visual] [--image PNG|--image-ref JSON] [--crop x,y,w,h] Ranked search of layer names and full text with instance overrides, text/boolean properties and swaps applied; exact node refs (including I…;… sublayer ids for inspect), match reasons, UTF-16 spans, coverage and cursor pages. Default 20 (1-200); hidden layers and internal pages need their flag. With --file/--workspace/--id instead of <file> it reads the workspace's prepared index (see index) --mode semantic|hybrid needs a configured model: see Optional semantic search.
models list|status|configure <profile> --model DIR [--runtime FILE]|remove <profile> Local text model for semantic search (bge-m3, experimental) and image model for image search (siglip-base, experimental); configure checks the files you downloaded and never downloads; remove keeps them. See Optional semantic search.
usages <file> <node|resource> [--scope ID] [--relation R[,R]] [--out] [--snapshot S] [--include-hidden] [--limit N] [--cursor C] Exact relations of one layer or resource (VariableID:…, StyleKey:…, image:…) in one stored scope, nested instances and swaps included: where a component, set, variable, style or image is used (default), or what a layer points at (--out). Each result keeps its exact ref, relation, state (resolved, missing, unresolved, …), basis and evidence; names never count as identity. No totals: coverage says complete or partial. Default 50 (1-200). With --file/--workspace/--id instead of <file> it reads the workspace's prepared index of --scope. With --out, a use of a cached library copy also names its library {kind, namespace, key}.
usages --file|--workspace|--id … --library <kind> --namespace <ns> --key <key> [--definition-source ID --definition-snapshot SNAP --definition-node NODE] [--source ID] [--scope ID] [--include-hidden] [--limit N] [--cursor C] Layers that use one library component, style or variable (kind), as each file's cached copy records it, across every source's prepared --scope (--source narrows to one). The definition stays unresolved unless the three --definition-* flags select it by exact ref (selected, keyEvidence: unverified); coverage lists each source's state and why it is partial. Name it from the library field of usages --out on a layer that uses it.
diff <old.fig> <new.fig> [--node ID] [--limit N] [--cursor C] [--json] What changed between two saved revisions: one line per changed top-level frame with counts per facet (text, layout, appearance, properties, structure, bindings); --json adds old/new field values and edge changes. Layers match by exact id and type only; a same-name or same-place frame is only a labelled possible match, and a side that stopped short, or a layer whose only difference is a field it could not read, reports unknown, never removed or changed. Pages of 100 changes (1-500) A side that stopped at a limit prints stopped early instead of no changes; narrow it with --node.
inspect <file> <node> [--depth N] [--images] [--states] [--compare-variant ID] [--compare ID] [--flat] [--full-text] [--colors] Compact expanded layout/text summary, at most 200 nodes. --images adds bitmap dimensions and crop footprints. --flat prints one line per node instead: position relative to the node, size, text, font, fill, stroke, radius, auto-layout, alignment, fixed/fill sizing, shadows and blurs --full-text returns each text in full (up to 10,000 characters); --colors adds visible solid fills (hex, opacity, bound variable), also on --flat; no gradients, images or strokes.
nodes <file> <node> The per-node object of a REST nodes response (document, components, componentSets, styles): expanded instances and overrides, auto-layout, text styles, fills, effects, bound variables, component properties, render bounds
nodes <file> --frames <list>, --frames - (stdin), --ids <node>... One decode, many nodes: one JSON line per listed id, the nodes output with its nodeId, or {nodeId, error}
variables <file> [node]
variables <file.fig> --format dtcg --collection ID --mode ID --out FILE
Default: unchanged REST-shaped bound/local variables. DTCG 2025.10 export: exact collection/mode IDs, no node; colors and unitless numbers only. Create the output directory first; diagnostics fail the whole export without changing the output. A library collection exports from the copies cached in the file (libraryCopy: true). An alias into another collection exports that collection's value, recorded in aliasOf; several target modes need --alias-mode COLLECTION=MODE.
bundle <file> <node> <out.zip> [--states] A design bundle for one frame; prints {nodeId, path, warnings}
bundle <file> --frames <list> --out-dir <dir> [--jobs N] [--states], --frames - (stdin) Many bundles from one decode, in parallel
verify <bundle> [--fonts <dir>] Check a bundle .zip or its extracted directory against its manifest: verified, missing and changed files, missing assets, the font faces to confirm in the project, and findings: each missing, unsupported or unverified handoff input with its nodes, evidence and next action; a face with a font file on this machine or in --fonts <dir> (a project folder, which also yields an @font-face) is local_file, not proof the browser loads it
export <file> <node> <out> [--bounds layout] [--scale N] [--quality 1-100] [--max-kb N] [--max-size N] [--match-dir DIR] [--hide ID[,ID]] SVG, PNG, JPG, WebP or AVIF; PNGs up to 4,194,304 pixels are automatically losslessly optimized, with decoded RGBA unchanged; original encoded bytes are kept unless smaller, and larger PNGs use regular encoding; --max-kb lowers lossy quality until it fits (PNG fails if still over budget, with no lossy fallback); --bounds layout exports the layout box instead of the render bounds; --match-dir DIR (SVG only, subfolders included) lists the SVGs there that draw the same outlines (matches) and up to 10 similar shapes with a score (similar); --hide ID[,ID] draws those layers inside the node as hidden over the same area, so diffing it with the plain export shows where that layer, as figlens draws it, changes the result (no difference does not prove the skipped rendering is harmless)
export <file> --frames <list> --out-dir <dir> [--format F] [--scale N] ..., --frames - (stdin) One decode, many exports (default png): writes <dir>/<nodeId>.<format>, one JSON line per id, the export output with its nodeId, or {nodeId, error}
export <file> --batch <items.json>, --batch - (stdin) One decode, many exports, each with its own options: a JSON array of 1-64 {node, out, bounds?, scale?, quality?, maxKb?, maxSize?, hide?} (MCP export_batch). Prints one manifest {count, failed, items}: per item the export output, or {error} (the others still export); a malformed item or a repeated out fails before any write
preview <file> [node] [--out preview.html] [--port N] [--bind IP] Local viewer that never writes the design; Semantic/Hybrid ranked search after its Enable index; --out writes a standalone offline snapshot; results and copied context name the page and, live, the loaded file path, source snapshot and local revision (unknown offline, where the path is never embedded); context also carries the reference scope's coverage, complete: null when unchecked. Visual/Hybrid accepts a reference PNG or selected layer with a pixel crop. Enable visual indexing explicitly; query images are not stored.
compare <file> <nodes.json> <node> Diff against a REST export of the same frame
compare-image <file> <node> <screenshot.png> Compare a screenshot of the built screen with the node rendered at its scale (--scale, --limit, --out diff.png, --full-page for a whole-page capture shorter than the frame; MCP compare_image). Prints mismatch, nonTextMismatch and the largest differing regions in node pixels, each with the deepest layers under it; text: true marks regions over text (often font fallback; review each)
node <file> <node> One raw .fig node
index prepare|refresh|rebuild|clear|status|add|remove|relocate|reset|track|untrack|embed|visual Local workspace in the per-user figlens state directory, or under a --storage DIR that the workspace then remembers. prepare <file> --scope NODE builds that scope's search index once; then search --file <file> (or --workspace DIR) answers without parsing, ranked across the workspace's sources. refresh rebuilds changed files, rebuild all or one --source/--scope, clear drops unused indexes; the previous index serves until a new one is ready. reset removes only the workspace database, never designs, exports or the remembered location. track --scope NODE records that scope's changes from a baseline build; untrack stops, keeping its history. embed embeds published scopes with the configured model, using CPU and memory; run it only when you want semantic workspace search. visual --scope NODE renders that published scope's screens and components for image search, embedding them when a vision profile is configured; run it only when you want visual workspace search.
jobs status|cancel <jobId> Show or cancel an index build; cancel returns after the build stopped
changes --file <file>|--id ID|--workspace DIR [--source ID] [--scope NODE] [--consumer NAME|--subscription ID|--cursor C] [--revision R] [--limit N] Recorded changes of tracked scopes, oldest first: one revision per published build (baseline or changes) with coverage and counts per change kind and facet; each changes revision has an impact summary of the layers its changes reach (null before schema 7); --revision pages that revision's changed nodes, then the layers its impact lists (entry says which); tracking says when a scope needs index refresh to record a change. Reads only
watch ack --file <file>|--id ID|--workspace DIR --consumer NAME|--subscription ID --cursor C [--source ID] [--scope NODE] Move a consumer's checkpoint to the nextCursor of the last changes page it handled with the same filters; repeating it is safe, and it only moves forward except that a current recovery cursor moves a checkpoint behind a deletion back to replay the kept revisions; a cursor issued before retention deleted revisions it had not passed is event_gap and writes nothing
watch run --file <file>|--id ID|--workspace DIR --scope NODE [--source ID] [--request-id R] Hold a lease on a tracked scope in the foreground: the workspace's shared runner refreshes it on each save (polled every 250 ms, content checked every 60 s), so changes shows new revisions with no index refresh. Prints the lease, then one end line when stdin closes, on Ctrl-C or SIGTERM, or when the scope is untracked. MCP watch start and stop hold leases while the server runs; an unrenewed lease ends after 30 s and the runner exits after the last one
watch status --file <file>|--id ID|--workspace DIR The workspace's leases (active, unauthorized, untracked, expired, ended) and runner (running, stopping, stopped, unknown, with its placement); never writes
watch subscribe --file <file>|--id ID|--workspace DIR --consumer NAME --source ID [--scope NODE] [--node ID] [--owner NAME] Follow a source, scope or exact layer (--node) from its newest revision with its own checkpoint, read with changes --subscription and acked with watch ack --subscription; a missing or ambiguous layer is target_missing or identity_uncertain, never a same-name match; --owner makes it temporary for that task
watch subscribe --file <file>|--id ID|--workspace DIR --consumer NAME --source ID --query TEXT [--type T[,T]] [--scope NODE] Save a search of one source's scope: its top 50 are evaluated now; changes --subscription reads the stored evaluations and never computes one
watch subscribe --file <file>|--id ID|--workspace DIR --consumer NAME --sources visible|ID[,ID] --query TEXT|--library KIND --key KEY [--namespace NS] [--definition-source ID --definition-snapshot SNAP --definition-node NODE] Save a search, or a library item's uses with their definitionMatch, over a fixed set of at most 10 sources (visible is resolved now; later sources are never added): delta.changedSourceIds names sources with new bytes, corpus_changed a set change, coverage.transitive is not_followed and delta.notFollowedSourceIds names changed sources holding no use, whose dependents were not re-checked; removing a member disables it (unsubscribe, then subscribe again)
watch evaluate --file <file>|--id ID|--workspace DIR --subscription ID Store a query subscription's evaluation of the scope's current index, unless it is already evaluated; a watch on the scope does this after each publication
watch list --file <file>|--id ID|--workspace DIR [--consumer NAME] [--after ID] [--subscription ID] List the visible subscriptions and their state, a page at a time; --subscription reads only that one (empty when not visible)
watch unsubscribe --file <file>|--id ID|--workspace DIR --subscription ID|--consumer C --owner NAME Remove one subscription and its checkpoint, or an owner's temporary ones; tracking and history stay
watch forget --file <file>|--id ID|--workspace DIR --consumer NAME [--source ID] [--scope NODE] Remove a consumer's raw checkpoints; a consumer keeps at most 64 subscriptions and checkpoints and a workspace 4096, and nothing is evicted automatically
mcp Local MCP server over stdio
update Replace the binary with the latest release

For related component variants, use inspect --states or bundle --states (MCP states: true, default false; no configuration change). Evidence retains source, unknown and truncation markers. Bundles add design/states.json and a context.md summary. See state evidence for scope and limits.

To compare two variants in the same component set, use inspect <file> <variantA> --compare-variant <variantB> (MCP compareVariant). variantComparison reports stored field/value-multiset differences with source IDs and unknowns; descendants pair by unique name, then by main component, then by stacking order among equal-sized same-name groups (pairedNodes, with per-pair changes; check pairedBy, order is the weakest evidence; the rest are unpaired), and bound variables are named. See comparison limits.

To compare any two nodes of one file (an empty and a filled screen, mobile and desktop breakpoints, two screens sharing a header), use inspect <file> <nodeA> --compare <nodeB> (MCP compare). comparison has the same shape plus rootDelta (size and parent-relative position); children pair by unique name, then by main component, then by stacking order among equal-sized same-name groups (pairedBy says which), the rest stay unpaired with reason: ambiguous-name, and instances are not expanded. A node and its own ancestor cannot be compared. --compare-variant still requires the same component set.

A node argument accepts 12:345, 12-345 or a Figma URL with ?node-id=. <file> can also be gs://bucket/object, downloaded with your gcloud login and cached. See the GCS snapshot cookbook for a fixed-object handoff, access requirements and refresh limits. Each CLI call decodes the file; MCP reuses the last unchanged local file, while remote calls parse again. Run figlens --help or figlens inspect --help (also -h) for full CLI usage. index add gs://bucket/object registers a pinned copy of that generation and reports remote {uri, generation}; only add runs gcloud.

inspect includes recorded text resizing, truncation, max lines and decoration. A parent without auto-layout carries childSpacing: "derived": gaps between its children are coordinate differences, not an auto-layout rule; constraints may still pin them. handoffDiagnostics reports known stored semantics not emitted, with counts, examples and coverage limits. Outputs protect the source and replace the destination only after a completed write. MCP limits request lines to 1 MiB and complete replies to 8 MiB; over-budget replies return an explicit error. Full CLI JSON remains available.

This page is built from docs/README.md in the repository.