# How the Brand Kit Extracts Design Systems from Figma in Agent-Native

> Learn how the brand kit extracts design systems from Figma by uploading `.fig` files for asynchronous indexing. Monitor the process with job identifiers for efficient design system management.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-29

---

**The brand kit extracts design systems from Figma by uploading the raw `.fig` file to a server endpoint, streaming it to Builder's remote service, and returning job identifiers that let users monitor the asynchronous indexing process.**

The BuilderIO/agent-native repository provides a seamless bridge between Figma files and reusable design systems. When you import a Figma file into the brand kit, the system validates the upload, streams the binary data to Builder's backend, and generates a centralized design system containing colors, fonts, and spacing tokens. This architecture avoids local parsing of the proprietary Figma format while ensuring design tokens remain centrally accessible.

## Uploading the Figma File from the Client

The extraction process begins in the **Design System Setup** page, where users select a `.fig` file through a file picker interface.

### The File Selection Handler

In [`templates/design/app/pages/DesignSystemSetup.tsx`](https://github.com/BuilderIO/agent-native/blob/main/templates/design/app/pages/DesignSystemSetup.tsx), the `handleFigImport` function constructs a `FormData` payload and POSTs it to the `/api/import-figma-system` endpoint:

```tsx
const handleFigImport = useCallback(
  async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file?.name.toLowerCase().endsWith('.fig')) return;
    const body = new FormData();
    body.append('file', file);
    const res = await fetch(appApiPath('/api/import-figma-system'), {
      method: 'POST',
      body,
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json?.error ?? 'Upload failed');
    setFigResult(json);               // ← stores Builder result
  },
  [],
);

```

This client-side handler performs basic extension validation before delegating the heavy lifting to the server.

## Server-Side Validation and Forwarding

The API route processes the multipart request and prepares the data for Builder's indexing service.

### Parsing the Multipart Request

In [`templates/design/server/handlers/import-figma-system.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/design/server/handlers/import-figma-system.ts), the `importFigmaSystem` handler parses the request body, enforces a **200 MiB** size limit, and sanitizes the filename into a suggested title:

```ts
export const importFigmaSystem = defineEventHandler(async (event) => {
  const parts = await readMultipartFormData(event);
  const part = parts?.find(p => (p.name === 'file' || p.name === 'fig') && p.data);
  if (!part) return { error: 'No .fig file uploaded' };

  // Validate size (max 200 MiB)
  if (part.data.length > MAX_FIG_BYTES) {
    setResponseStatus(event, 413);
    return { error: `File too large (max ${MAX_FIG_BYTES / 1024 / 1024} MB).` };
  }

  const suggestedTitle = (part.filename || 'Imported brand')
    .replace(/\.fig$/i, '')
    .replace(/[-_]+/g, ' ')
    .trim();

  return await startBuilderDesignSystemIndex({
    projectName: suggestedTitle,
    files: [{ name: part.filename || 'brand.fig', data: part.data, mimeType: 'application/octet-stream' }],
  });
});

```

The `MAX_FIG_BYTES` constant ensures uploads do not exceed the service capacity before forwarding to the core indexing logic.

## Streaming to Builder's Remote Service

The actual extraction occurs entirely within Builder's backend infrastructure. The agent-native code acts as a secure conduit, handling credentials and upload orchestration.

### The Core Indexing Function

In [`packages/core/src/server/builder-design-systems.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/builder-design-systems.ts), the `startBuilderDesignSystemIndex` function manages the three-phase upload process:

```ts
export async function startBuilderDesignSystemIndex(
  options: BuilderDesignSystemIndexOptions,
): Promise<BuilderDesignSystemIndexResult> {
  const credentials = await resolveBuilderDesignSystemCredentials();

  // 1️⃣ Create upload session → get resumable URLs
  const uploadStart = await fetchWithTimeout(
    makeBuilderDesignSystemUrl('upload/start', credentials),
    { method: 'POST', headers: makeBuilderHeaders(credentials), body: JSON.stringify({ attachments: ... }) }
  );
  const slots = (await uploadStart.json()).uploads ?? [];

  // 2️⃣ Upload each file
  for (let i = 0; i < slots.length; i++) {
    await uploadToResumableUrl(slots[i], files[i]);
  }

  // 3️⃣ Trigger the indexing job
  const generate = await fetchWithTimeout(
    makeBuilderDesignSystemUrl('generate', credentials),
    { method: 'POST', headers: makeBuilderHeaders(credentials), body: JSON.stringify({ uploads: uploadTokens, projectName: options.projectName }) }
  );

  const generated = await generate.json();
  return {
    ok: true,
    source: 'builder',
    projectId: generated.projectId!,
    jobId: generated.jobId!,
    designSystemId: generated.designSystemId!,
    suggestedTitle: options.projectName?.trim() || null,
    builderUrl: builderDesignSystemUrl(generated.designSystemId!),
    status: 'in-progress',
  };
}

```

### Credential Resolution and Upload Flow

The function first resolves **Builder credentials** using `BUILDER_PRIVATE_KEY` and `BUILDER_PUBLIC_KEY` environment variables. It then creates a resumable upload session with Google Cloud Storage, streams the raw `.fig` binary to the provided URL, and finally POSTs a `generate` request to start the asynchronous indexing job. The returned `BuilderDesignSystemIndexResult` contains the unique identifiers required to track the job.

## Displaying Indexing Results and Job Status

Once the server returns the result, the front-end stores it in the `figResult` state. The `FigImportPreview` component renders the job identifiers and provides a direct link to the Builder design system:

- **projectId**: The Builder project containing the indexed system
- **designSystemId**: The unique identifier for the brand kit reference
- **builderUrl**: A direct URL to view and manage the extracted tokens
- **status**: Always returns `"in-progress"` initially, indicating the asynchronous processing has begun

Users can reference this design system by its `designSystemId` for subsequent operations like asset generation or design system indexing.

## Summary

- **File upload**: Users select `.fig` files in [`DesignSystemSetup.tsx`](https://github.com/BuilderIO/agent-native/blob/main/DesignSystemSetup.tsx), which POSTs to `/api/import-figma-system` using `handleFigImport`.
- **Server validation**: The `importFigmaSystem` handler enforces a 200 MiB limit and sanitizes filenames before forwarding.
- **Builder integration**: `startBuilderDesignSystemIndex` in [`builder-design-systems.ts`](https://github.com/BuilderIO/agent-native/blob/main/builder-design-systems.ts) handles credential resolution, resumable uploads, and job creation.
- **Asynchronous processing**: The design system extraction happens remotely on Builder's backend, not locally.
- **Result tracking**: The system returns `projectId`, `jobId`, and `designSystemId` for monitoring via `FigImportPreview`.

## Frequently Asked Questions

### What file format does the brand kit support for Figma imports?

The brand kit exclusively supports **`.fig` files**—the native Figma binary format. The client-side validation in [`DesignSystemSetup.tsx`](https://github.com/BuilderIO/agent-native/blob/main/DesignSystemSetup.tsx) explicitly checks for this extension before initiating the upload.

### Is there a file size limit when uploading Figma files?

Yes. The server handler enforces a **maximum file size of 200 MiB** (approximately 200 MB). Files exceeding this limit return a 413 error status with an appropriate message before any data reaches Builder's remote service.

### Where does the actual design system extraction happen?

The extraction occurs **entirely on Builder's backend service**. The agent-native code only handles credential resolution, file streaming, and job initiation. It does not parse the proprietary Figma binary format locally; instead, it delegates to Builder's design-system indexing infrastructure.

### How can I check the status of an imported design system?

The `startBuilderDesignSystemIndex` function returns a `BuilderDesignSystemIndexResult` containing a `builderUrl` field. You can navigate to this URL to view the indexing status and access the extracted design tokens. The `FigImportPreview` component automatically renders this link in the UI immediately after upload.