> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
title: How Unframer Works
sidebarTitle: How It Works
description: Understand the architecture behind exporting Framer components to React.
icon: lucide:cpu
---

# How Unframer works

Unframer converts your **Framer components** into React component files (`.jsx` by default) that render as native React components. No iframe, no embed. The generated components run in your React app with the lightweight `unframer` runtime package.

```diagram
┌────────────────────┐            ┌────────────────────────┐            ┌────────────────────┐
│   Framer Editor    │            │   Unframer Database    │            │   Your React App   │
│                    │   Plugin   │                        │    CLI     │                    │
│  Design your       ├────────────►Stores component       ├────────────►.jsx components    │
│  components        │   export   │JavaScript URLs        │   bundle   │chunks/*.js         │
│                    │            │and metadata            │            │styles.css          │
└────────────────────┘            └────────────────────────┘            └────────────────────┘
```

## The export pipeline

**Step 1: Plugin collects metadata.** When you click Export in the React Export plugin, it reads all selected components from the Framer SDK: their JavaScript URLs, property controls, breakpoints, color styles, and page structure. This data is sent to the Unframer API.

**Step 2: CLI fetches and bundles.** When you run `npx unframer {projectId}`, the CLI fetches each component's JavaScript URL from Framer's CDN. These URLs point to ES modules that Framer uses internally to render your site.

**Step 3: esbuild bundles everything.** The CLI uses esbuild to resolve all dependencies, inline Framer's internal modules, and produce `.jsx` entry files plus shared `chunks/*.js` files. Code splitting keeps shared code deduplicated. External npm packages used in your Framer code components are resolved and installed automatically.

**Step 4: Types are generated.** Unframer runs each component in Node.js and reads the `propertyControls` field. These controls (the inputs you see in Framer's right panel) are converted into **JSDoc type comments** injected directly into the `.jsx` files. Variants become union types, images become `{src, srcSet, alt}` objects, etc. Your editor picks up these types for autocomplete and type checking without separate declaration files.

**Step 5: Styles are extracted.** A `styles.css` file is generated containing Framer's base styles, the fonts used in your components, and your **color styles** as CSS variables (prefixed with `--unframer-`).

<Aside>
  <Info>
    The exported files are **generated code**. Never edit them manually. Re-run the CLI after making changes in Framer.
  </Info>
</Aside>

## What gets exported

| Output               | Description                                              |
| -------------------- | -------------------------------------------------------- |
| `component-name.jsx` | React component entry file with JSDoc type comments      |
| `chunks/*.js`        | Shared bundled chunks imported by component files        |
| `styles.css`         | Base Framer styles, fonts, and color style CSS variables |

## When to re-run the plugin vs the CLI

The **plugin** saves component metadata to the Unframer database. The **CLI** downloads the latest component JavaScript from Framer's CDN.

| Change in Framer                       | Action needed                              |
| -------------------------------------- | ------------------------------------------ |
| Edit existing component content/layout | Re-run CLI only (after publishing)         |
| Add a new component                    | Re-open plugin, select it, then re-run CLI |
| Change color styles                    | Re-open plugin, then re-run CLI            |
| Add new pages                          | Re-open plugin, then re-run CLI            |
| Add new locales                        | Re-open plugin, then re-run CLI            |
| Change breakpoints                     | Re-open plugin, then re-run CLI            |

<Aside>
  <Tip>
    **Publishing is required.** Framer only updates the JavaScript modules behind component URLs when you click the **Publish** button. The CLI reads from these published URLs.
  </Tip>
</Aside>

## Server-side rendering

Unframer components support **SSR** out of the box. They render on the server just like any React component, giving you the same SEO and performance characteristics as a Framer-hosted site. The `styles.css` file ensures fonts and base styles load correctly during SSR.

## Future compatibility

Framer occasionally updates their runtime. Unframer tracks these changes automatically via GitHub Actions, updating the internal [framer.js runtime](https://github.com/remorses/unframer/blob/main/unframer/src/framer.js). An [example app](https://unframer-nextjs-app.vercel.app/) is deployed on every change, making regressions easy to catch and fix.

## Supported component props

Unframer generates TypeScript definitions for all your Framer **component variables**:

* **`variant`** — union type of all variant names
* **Functions** — from `event` variables in Framer
* **Scalars** — string, number, boolean, date
* **Image** — `string` (URL) for basic image controls
* **Responsive image** — `{ src: string, srcSet?: string, alt?: string }`
* **Link** — string URL
* **Color** — CSS color string
* **Component slot** — `React.ReactNode` (from `component` variables like Ticker)
