Sitemap

How to get your design system into Figma Make

Every problem I ran into getting my design system from a monorepo into Figma Make, and how to solve them

9 min readJan 31, 2026

--

Once your design system is in Figma Make, you can really reap the benefits of working with design and code side by side and start actually using your system. But pulling it out of a monorepo? That’s where things get tricky

This article walks through the specific problems I ran into and the solutions that worked. It’s not prescriptive — your setup will likely differ. But, if any of these sound familiar (monorepos, pnpm workspaces, internal packages, patched dependencies), you’ll find practical fixes here.

The basics

Figma Make consumes React component libraries published to npm.

The high-level process:

  1. Build your package — Bundle your React components into a distributable format
  2. Publish to npm — Either public npm or Figma’s private registry for your org
  3. Install in Figma Make — Ask the AI to install your package, or add it to package.json manually
  4. Add guidelines — Write markdown files that teach Figma Make how to use your components correctly
  5. Publish as a template — Share the configured file so your team can use it as a starting point

If you’re new to npm publishing, the npm documentation covers the fundamentals. Figma’s own docs on bringing your design system package and writing guidelines are worth reading before you start.

For simple setups, this is straightforward: Build, publish, install, done.

The rest of this article is about what happens when your setup isn’t quite so simple

My setup

For context, here’s the techstack I’m working with

  • A monorepo with pnpm workspaces
  • Patched packages — where we’ve made modifications to node_modules
  • Catalog dependencies for centralised version management
  • Internal packages for design tokens, icons, and component-dependent business logic
  • tsdown

None of this is unusual for a production design system. But each one adds complexity to the publishing process. These also aren’t specific requirements for you to be able to publish a design system — and your system will likely vary.

If any of those sound familiar, you may hit some of the same walls I ran into trying to get a Design System onto Figma Make. What follows will hopefully set you up for success to navigate some of the difficulties I faced.

1. Creating a Figma-Specific Build Script

When trying to get your design system out of a monorepo your standard build process probably won’t work.

Our goal here is to have our design system package exist standalone without any dependencies on other packages within our monorepo. The alternative would be to publish all your dependencies to the registry — however that comes with a few tradeoffs: more packages to manage, extra coordination around breaking changes, and a higher risk of dependency hell and version mismatches.

You’ll need a dedicated script that handles the differences between a regular build and a Figma specific build.

At minimum, your Figma build script needs to:

  • Clean the output directory
  • Run your bundler with Figma-specific config
  • Generate a modified package.json with resolved dependencies
  • Copy any additional assets (e.g uncompiled CSS for theming)

I’d recommend a standalone script rather than trying to extend your existing build. The concerns are different enough that mixing them gets messy.

Add explicit logging at each step. When something breaks, you want to know exactly where. Log what dependencies you’re resolving, what you’re removing, what you’re bundling. This saves hours of debugging later.

2. Use a separate bundler config for Figma

Your normal bundler config will be optimised for web apps; Figma make has a few different constraints for us to work with.

I use a dedicated tsdown config that:

  • Treats React, React DOM and a few heavy libraries as externals (Figma Make can install them itself)
  • Bundles internal workspace packages, and patched packages

Here’s a basic example you can extend and modify for your own use:

import pkg from './package.json' with { type: 'json' };
function packageToRegExp(pkgName: string): RegExp {
return new RegExp(`^${pkgName.replace('/', '\\/')}(\\/.*)?$`);
}
// Externalize peer deps and heavy deps - Figma Make installs these itself
// Explained in Step 3
const external = [
'react',
'react-dom',
'use-sync-external-store',
'@contentsquare/csq-icon-react',
'@hookform/resolvers',
'@tanstack/react-table',
'recharts',
'react-day-picker',
'react-hook-form',
'd3-array',
'date-fns',
'zod',
].map(p => packageToRegExp(p));

// Force‑bundle workspace deps and patched packages
// Explained in step 3
const noExternal = [
packageToRegExp('@my-designsystem/design-tokens'),
packageToRegExp('@my-designsystem/icons'),
packageToRegExp('cmdk'), // Patched to add CommandItemStatic
];
export default defineConfig(
{
pkg,
},
{
entry: {
react: 'src/main.tsx',
utils: 'src/utils/index.ts',
styles: 'src/styles.ts',
},
outDir: 'dist-figma',
external,
noExternal,
env: {
NODE_ENV: 'production',
},
platform: 'browser'
},
);

This is a high level example, but the basic concepts can be applied to most modern build tools, and will need you to define your own dependencies.

3. Removing Unnecessary Dependencies

Not everything in your design system needs to go to Figma Make

Look at your dependencies and ask: does this make sense for code generation?

For example, my design system exports both React and Vue components using Veaury, but Figma Make only uses React components. You probably don’t need that tracking library either. Get rid of it.

The fewer things we need to worry about, the fewer things that can go wrong.

This is different from marking something as external. We’re removing it from the published manifest entirely. The components that depend on these libraries shouldn’t be exported from your Figma bundle at all.

4. Bundling Patches

If you’re using patches, such as pnpm-patch or patch-package this is critical.

Figma Make doesn’t use your repository. It installs packages fresh from npm. Any exports or fixes you’ve added via patches won’t exist in their environment.

The failure is silent. Your build succeeds, the import looks normal. Then it crashes at runtime when Figma Make tries to call a function that was never there.

** You can tell a builds failing in Figma Make when you see the infinite spinner, and 503 errors in the console **

You have two options:

Bundle the patched dependency — Force it into your output so Figma Make never tries to install it separately. In your bundler config, add patched packages to noExternal (or equivalent) so they’re included in your bundle rather than treated as external dependencies.

Exclude the affected components — If the patched functionality is only used by complex interactive components that don’t work well in Figma Make anyway, just don’t export those components.

Add a check to your build script that scans your patches directory and warns about anything that isn’t explicitly handled. You don’t want to discover this problem after publishing.

5. Handling workspace dependencies

If you’re using `workspace:*` or `workspace:^` for sibling packages, you need to decide: bundle them, or publish them separately?

Bundling is simpler. The dependencies get included in your main package. One publish, one package. But your bundle gets larger, and you can’t version the dependency independently

Separately keeps things modular. Your main package declares a dependency. There’s more moving parts to maintain, but it can be a cleaner operation.

Either way, you must resolve the workspace protocol. Figma Make can’t interpret workspace — it needs actual semver ranges.

For bundled dependencies, add them to your noExternal config and remove them from the published package.json.

// Resolve workspace protocol
if (version.startsWith('workspace:')) {
const pkgJson = JSON.parse(fs.readFileSync(join(packageDir, 'package.json'), 'utf8'));
resolved[name] = `^${pkgJson.version}`;
}

If you’re using pnpm catalogs for centralized versioning, you’ll need similar resolution logic. The lockfile format is inconsistent — I ended up with multiple fallback regex patterns to handle the different cases. Read your catalog file directly when possible rather than parsing lockfile output.

if (version.startsWith('catalog:')) {
// Try to extract version from lockfile - format is '@package/name@version:'
const escapedName = escapeRegex(name);
const directMatch = lockfileContent.match(new RegExp(`'${escapedName}@([^']+)':`));
const catalogMatch = lockfileContent.match(
new RegExp(`\n\s+${escapedName}:\n\s+specifier: [^\n]+\n\s+version: ([^\n]+)`),
);
const overrideMatch = lockfileContent.match(new RegExp(`\n\s+${escapedName}: ([^\n]+)`));
const simpleMatch = lockfileContent.match(new RegExp(`\n\s*${escapedName}:\s*([^\n\s]+)`));
// Fallback: find any version of the package (non-scoped only)
const anyVersionMatch = !name.includes('/')
? lockfileContent.match(new RegExp(`\n ${escapedName}@([^':\n]+):`))
: null;
const resolvedVersion = directMatch?.[1] || catalogMatch?.[1] || overrideMatch?.[1] || simpleMatch?.[1] || anyVersionMatch?.[1];
if (resolvedVersion) {
resolved[name] = `^${resolvedVersion}`;
console.log(` Resolved ${name}: catalog: → ^${resolvedVersion}`);
} else {
resolved[name] = '*';
console.warn(` ⚠️ Could not resolve ${name}, using '*'`);
}

6. Validate before publishing

Don’t publish to find out if your build works. Test it locally first.

Use pnpm link (or your alternative)

In your Figma build output directory:

cd dist-figma
pnpm link - global

Then in a test project:

pnpm link - global your-package-name

I recommend you download a Figma Make project as a test project

Download code button in the top right of the Figma Make interface

This lets you import your package locally and verify the exports work, the dependencies resolve, and nothing crashes on import.

Check your package.json

Before publishing, inspect the generated package.json in your output directory. Verify:

  • No workspace: or catalog: protocols remain
  • No internal packages that shouldn’t be published
  • No dev dependencies that got included
  • Exports point to the right files

Test your bundle size

If your bundle is unexpectedly large, something likely got included that shouldn’t have. Check your externals config, React and React DOM should definitely be external.

7. Set up Publishing Credentials

Figma provides a private npm registry for your organisation. You’ll need to configure authentication.

In your Figma Make file, go to Make Settings → Figma npm registry. An org admin needs to generate the registry key. You’ll get a code snippet for your .npmrc:

@your-org:registry=https://registry.figma.com/
//registry.figma.com/:_authToken=${FIGMA_NPM_TOKEN}

Set the FIGMA_NPM_TOKEN environment variable in your build environment. Don’t commit the token to your repo.

8. Version Management

For automated publishing, you’ll also want to handle version conflicts. Figma’s registry doesn’t auto-increment versions. If you try to publish a version that already exists, you get a 409 error.

Query the registry before publishing to get the current version, then increment:

const response = await fetch(`https://registry.figma.com/packages/${packageName}`, {
headers: { 'Authorization': `Bearer ${process.env.FIGMA_NPM_TOKEN}` }
});
const data = await response.json();
// Increment from data.version

This saves you from manually bumping versions and hitting conflicts.

I’d also recommend adding a custom suffix to the Figma specific package. For example: 1.2.3-figma-1

This lets you keep the semver of the DS package separate from any minor bumps you might need to do to get a Figma build working

9. Publish

With everything configured, publishing itself is straightforward:

cd dist-figma
npm publish

If you’ve set up version auto-increment, run your build script first to generate the correct version. Or add a custom publish npm script into your package json.

Watch the output for any warnings about missing files or invalid package structure. A successful publish doesn’t guarantee everything works — it just means npm accepted the package.

10. Validate in Figma Make

Now test it in the actual environment.

Create a new Figma Make file. Ask the AI to install your package, or add it to package.json manually. Try using a few components.

Things to check:

  • Components import without errors
  • Props work as expected
  • Styles apply correctly (check your CSS got included)
  • No runtime errors in the console

If something doesn’t work, check whether it’s a bundling issue (dependency not included), an externals issue (dependency incorrectly externalised), or a patch issue (vanilla npm version missing your changes).

11. Writing guidelines

Getting your package into Figma Make is half the job. The other half is teaching it how to use your system properly.

Figma Make’s AI can inspect your package and figure out what components exist. But it doesn’t know your conventions — when to use Button versus IconButton, your spacing scale, which props are required, which combinations don’t make sense.

Every Figma Make file has a guidelines/ folder. The Guidelines.md file is the entry point. You can add additional markdown files for specific components or design tokens.

Think of it like onboarding documentation for a new engineer. What would they need to know to use your system correctly?

Be specific about tokens. List your spacing scale. Explain your semantic colour names.

Document component relationships. When should someone use Card versus Surface?

Include examples. Show the right way to compose components.

Keep it focused. More context isn’t always better. Structure your guidelines so the AI can find what it needs without reading everything.

Figma’s guidelines documentation covers structure and best practices in detail.

10. Publish as a Template

Once your Figma Make file is configured with your package and guidelines, publish it as a template. This gives your team a starting point with everything already set up.

You can publish just the configuration (package + guidelines), or include a starter app that demonstrates your system in use.

Templates are the distribution mechanism. Without one, every designer needs to manually install and configure your package.

Ongoing Maintenance

After the initial setup, publishing updates is simpler. But a few things to watch for:

New dependencies need decisions: external, bundled, or removed? Every new dependency is a potential failure point in Figma Make.

New patches need explicit handling. Don’t assume your build script will catch them.

Removed packages need cleanup across all configs, not just the main code.

Add a pre-publish checklist to your workflow. The problems that slip through are usually the ones you forgot to check.

Once it’s working, it stays working. The build script handles the complexity. Publishing becomes boring.

That’s the goal.

--

--

Luke Finch
Luke Finch

Written by Luke Finch

Director of Design, Serial project starter. Designer who codes. Lover of coffee.