Export to GitHub
The plugin creates a branch, commits your exported icons, and opens a pull request.
For this to work, your GitHub token must have write access to the repository.
Option A — Classic Personal Access Token (fastest)
- In GitHub, go to Settings → Developer settings → Personal access tokens (classic).
- Click Generate new token (classic).
- Choose scope(s):
- Private repos: check
repo(required). - Public-only repos: you can use
public_repoinstead.
- Private repos: check
- Generate the token and copy it.
Org repos with SAML SSO: after creating the token, click “Authorize” for your organization.
Without this, GitHub will return403 Resource not accessible by personal access token.
Option B — Fine-grained Personal Access Token (recommended for least privilege)
- In GitHub, go to Settings → Developer settings → Personal access tokens → Fine-grained tokens.
- Click Generate new token.
- Resource owner: choose your user or the organization that owns the repo.
- Repository access: select Only selected repositories, then pick your target repo.
- Repository permissions (at minimum):
- Contents: Read and write (create branches/commits)
- Pull requests: Read and write (open the PR)
- (Optional) Actions: Read/Write only if you plan to call Actions APIs directly.
- Create the token and copy it.
- If the repo is in an organization with SSO, click Authorize for that org.
Add token in the plugin
Open Settings in the plugin and fill:
- Repository owner (e.g. your GitHub username or your org name)
- Repository name (e.g.
design-system) - Token (paste the PAT from above)
Click Save, then run your export.
Troubleshooting
403 Resource not accessible by personal access token- Classic token missing
repo(private) orpublic_repo(public) scope. - Fine-grained token not granted to this repository, or Contents/Pull requests are not Read & write.
- Organization uses SAML SSO → token not Authorized for the org.
- Classic token missing
- Branch creation fails on
main- Protected branches block direct pushes. The plugin creates a feature branch; ensure your token has Contents: write and that the base commit SHA exists.
- Still stuck?
- Regenerate a classic PAT with
repoto quickly rule out permissions issues.
- Regenerate a classic PAT with
Example Design System repository
Jump‑start your setup
We provide a complete example Design System repository you can copy for a production‑ready icon workflow:
Icons directory:
src/icons/*CI job (GitHub Action) that automatically optimizes/normalizes icons and pushes updates to the PR
Storybook 9 Docs with examples and guidelines
Example flexible
Iconcomponent with propsExample Icons Gallery with advanced filters and click‑to‑copy
Repository: https://github.com/Sofian-Design/design-system-repository-demo
Storybook: https://sofian-design.github.io/design-system-repository-demo
See also: Design System Demo Repository
scripts/optimize-icons.mjs
import { readdir, readFile, writeFile } from 'fs/promises';
import path from 'path';
import { optimize } from 'svgo';
const ICONS_DIR = path.resolve('src', 'icons');
async function* getSvgs(dir) {
const dirents = await readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
const res = path.join(dir, dirent.name);
if (dirent.isDirectory()) {
yield* getSvgs(res);
} else if (res.endsWith('.svg')) {
yield res;
}
}
}
for await (const file of getSvgs(ICONS_DIR)) {
const source = await readFile(file, 'utf8');
const { data } = optimize(source, {
path: file,
multipass: true,
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
},
},
},
],
});
const colorized = data
.replace(/stroke="#([0-9a-fA-F]{3,6})"/g, 'stroke="currentColor"')
.replace(/fill="#([0-9a-fA-F]{3,6})"/g, 'fill="currentColor"');
await writeFile(file, colorized, 'utf8');
}