Syncing with a repository
Connect the document to a Git repository or an HTTP endpoint so tokens live next to the code that consumes them.
Read this before you start
Sync is the least finished area of the plugin.
- GitHub works. GitLab and custom HTTP endpoints are implemented but their domains are not in the plugin’s network allowlist, so Figma blocks those requests at runtime. Treat GitLab and URL as not usable today.
- There is no merge. A pull replaces your local tokens; a push overwrites the remote file.
- Access tokens are stored unencrypted in Figma’s local client storage.
- Some sync controls are only reachable through Settings — see below.
Adding a provider
Footer → Settings (gear) → sync provider → add sync provider.
GitHub Works
| Field | Default |
|---|---|
| Display name | — |
| Personal access token | — |
Repository (owner/name) | — |
| Branch | main |
| Path or folder | tokens.json |
| API base URL | https://api.github.com |
The token needs repository read and write access on the target branch.
GitLab Blocked
Fields mirror GitHub (project group/name, base URL https://gitlab.com, with
/api/v4 appended automatically), but gitlab.com is not in the plugin’s
allowed-domains list, so requests fail.
HTTP endpoint Blocked
An endpoint URL plus an optional Authorization header value. Pull is a GET,
push is a PUT of the whole document. Arbitrary domains are not in the
allowlist.
Single file vs directory mode
The path field decides the mode:
| Path | Mode | Result |
|---|---|---|
Ends in .json — tokens/tokens.json | Single file | One file holding the entire document |
Anything else — tokens/ | Directory | One JSON file per token set, plus $themes.json |
Directory mode is what you want in a repository — a change to button tokens
touches comp/button.json, not a 4,000-line blob.
Pull
Reads the remote and replaces the local tokens.
- Directory mode walks the path recursively and collects every
.jsonfile. - The payload is validated and converted to DTCG before being stored.
- Result: “Pulled N tokens from <name> ✨”. An empty result reports “No tokens found”.
While pulling, a full-screen overlay blocks interaction: “Pulling tokens from <name>… This may take a few seconds”.
Pull is destructive
Your local tokens are replaced, not merged. Export a backup first if the document holds work that is not in the repository.
On connect
Adding a provider immediately checks whether the remote already has tokens. If it does, a Remote tokens detected dialog offers Pull tokens or Not now, and states plainly that pulling replaces local data.
Push
Writes the current document to the remote.
- Single file — the whole
{ tokens, themes, tokenSets }object, pretty printed, committed with the message “Update design tokens via Figma plugin”. - Directory — one commit per token-set file, plus
$themes.jsonwhen themes exist.
There is no conflict detection: a push overwrites whatever is at that path on
that branch. Push to a working branch, not to main directly.
Known gaps
| Gap | Consequence |
|---|---|
| GitLab and URL domains are not in the network allowlist | Those providers cannot connect |
| No merge or conflict detection | Concurrent edits are lost, last write wins |
| Pull does not restore token set metadata | Set structure can be reconstructed from folder paths, but explicitly created empty sets are lost |
| Tokens are stored as plain JSON in client storage | Anyone with access to the machine’s Figma data can read them |
| Provider editing and removal are not exposed in Settings | Removing a connection is only possible from a panel that is not currently reachable in the UI |
| The push format switch (flat vs nested) has no UI | Directory push always uses the flat format |
A workable setup today
- Repository with a
tokens/directory on adesign-tokensbranch. - GitHub provider, path
tokens/, branchdesign-tokens. - Pull at the start of a session, push at the end.
- Review and merge to
mainthrough a pull request. - One person pushes per document — the lack of merge makes concurrent pushes unsafe.