Penpot
- Version
- 2.19.1
- Released
- 2026-11-11
- GitHub stars
- 62,286
- License
- MPL-2.0
- Last checked
- 2026-11-12
Design & prototyping · Independent guide
Explore Penpot for interface design. Start with the official web app, then read our documented tests before moving your own design files.
Scope of this guide. Explore Penpot as an open-source Figma alternative, with official access, documented Figma-to-Penpot migration, design and layout tests, component notes and backup guidance.
Hands-on tests, documented
No downloadable assets in this release.
Use on official website ↗Each result below is limited to the recorded samples and workflow.
A self-authored 10-object Figma file migrated through Penpot Exporter 0.26.3 and GUI import. Native text, a component link and one fixed layout row survived, with text-metric differences and a later PNG preview timeout. This was not direct .fig import or a full compatibility test. The earlier SVG/API test had different text and grouping limits.
Same-file, single-rectangle fill-color main-component change propagation was checked through the API: two instances followed the main color, one retained an override, and reset restored synchronization. Two forced reloads retained the recorded states. Pending: other properties, variants, nested components and cross-file shared libraries.
Pending: prototype interactions and navigation were not tested.
Pending: multiplayer editing, comments and sharing were not tested.
Pending: inspect-mode measurements, code output and a developer handoff workflow were not tested.
Pending: only the official cloud service was used; no self-hosted installation was tested.
Our newest Figma migration check is below. The earlier SVG, layout and backup experiments that follow retain their original scope; their results are not full-file migration claims.
Tested 2026-11-13 · Self-authored Figma file created through the plugin API · Penpot Exporter 0.26.3 · GUI export/import into Penpot official cloud · Plugin API checks and browser reload
A one-page Figma fixture contained 10 objects: a 600×420 frame, two native Inter text layers, a fixed 400×80 horizontal auto-layout row with 12-unit padding and a 16-unit gap, two 120×40 rectangles, and a 100×48 rectangle component with one linked instance. Penpot Exporter produced a 13,699-byte .penpot archive; its interface reported 3 seconds. Penpot’s GUI imported it as a separate file. All 10 non-root objects and both text strings were present. Text remained editable: a temporary title edit changed its measured width, then the original text was restored. Changing the main rectangle’s fill through the plugin API updated its instance; restoring the fill updated both. The row became Flex row-reverse with reversed child order, preserving the rectangles at (36,132) and (172,132). Increasing the row width to approximately 480 retained their fixed sizes and 16-unit gap; restoring width 400 and reloading retained the original recorded state and component link.
Scope and limits. This uses the Penpot Exporter conversion, not direct .fig import or an SVG reconstruction. Inter font names and sizes 28 and 16 survived, but text metrics differed: the title changed from 280×34 to 281×34 and the body from 312×19 to 309×20. The component check covered only one same-file rectangle fill; the layout check covered one fixed row, not nested, fill or hug migration. Complex components, variants, overrides, cross-file libraries, tokens, prototypes, collaboration, developer handoff, self-hosting, other fonts, images and cross-version recovery were not tested. A separate server-side PNG preview export returned HTTP 500 / ResourceRequest timeout. The design was visible in the browser, but a browser screenshot is not a successful PNG export. The reported 3 seconds is one small-file observation, not a performance guarantee or a lossless-migration claim.
The fixture was original synthetic artwork with no third-party images. Editing and export used the official plugin API. The browser was used for login, draft creation and naming, visual inspection and forced reload. This was not a complete manual GUI test. The browser automation tool refused local file access, so SVG file-picker upload was not verified; that tooling restriction is not a Penpot product failure.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Windows · Browser UA Chrome 157 · Official plugin API
A self-created 800×600 SVG with simple geometry and text was imported through createShapeFromSvg. Geometry, a 0.5 fill opacity and a 4-unit stroke survived. The API changed a button’s position, width and color, and created and edited a separate native text object. A local component instance accepted a color override and reset to its original color. Two named versions saved; a forced browser reload retained the edits, text and component instance. SVG and PNG exports passed independent dimension checks at 800×600; the PNG outer corner was transparent.
Scope and limits. The three imported SVG text objects became svg-raw, not native editable text. The inner card group was flattened and original IDs were not preserved as layer names. Creating new native text does not demonstrate conversion of imported text. Pending: SVG file-picker import, complete GUI usability, Figma file migration, font fidelity, advanced auto layout, interactive prototypes, collaboration, developer handoff and self-hosting. The recorded version is independent of the current release listing.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Official plugin API · Same file, single rectangle fill color
A self-created 120×60 rectangle became a main component with two instances, A and B. Changing the main fill from green (#236548) to blue (#3658a4) updated both instances. B was then overridden to red (#a43658). Changing the main fill to orange (#e5a048) updated A while B kept its override; a saved version and forced browser reload preserved that difference. Resetting B with resetOverrides restored orange. Changing the main fill back to green updated both instances again, and a second saved version and forced reload retained the result. Instance identities and object IDs stayed unchanged.
Scope and limits. Only same-file, single-rectangle fill-color changes were tested through the API. Pending: cross-file shared libraries, multiplayer collaboration, nested components, variants, text or size changes, manual GUI operations, performance, offline recovery and Figma migration. No propagation latency was measured. This does not establish correct propagation of every property. The earlier API export failure was not retested or resolved by this component experiment; see the separate GUI backup test below.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Official plugin API · Separate synthetic fixture
A 480×240 board contained three 120×60 rectangles with 20-unit padding, a 16-unit column gap and a 12-unit row gap. In row/wrap mode their positions were (20,20), (156,20) and (292,20). Reducing the board width to 300 moved the third rectangle to (20,92). Column/nowrap mode placed them at y=20, 92 and 164. Restoring row/wrap and width 480 restored the original coordinates. A named version saved; a forced browser reload retained the layout settings and coordinates.
Scope and limits. Fixed-height limit: in column mode the last rectangle ended at y=224, leaving 16 units below it in the 240-high board, less than the configured 20-unit padding. The three rectangles, two row gaps and both padding edges require 244 units of height. This does not demonstrate automatic height growth or overflow-free layout. Only fixed-size rectangles were checked through the API, not manual GUI layout editing. Simple rectangle fill/auto sizing is covered separately below. Simple English dynamic text is covered separately below. Pending: complex hug/fill sizing, more complex nested layouts, grid, real Figma layout migration and production responsive behavior.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Official plugin API · Separate single-layer rectangle fixtures
A horizontal 400×160 container had 20-unit padding, a 16-unit gap, an 80×60 fixed rectangle and a second rectangle set to fill width. The fill rectangle measured 264 units wide; reducing the container width to 300 reduced it to 164. In a separate 300-wide vertical container, three rectangles with heights 40, 60 and 80, 12-unit gaps and 20-unit padding produced an automatic height of 244. Increasing the middle rectangle to 100 raised the container height to 284. Restoring it to 60 restored approximately 244 (the API returned 243.99999999999997). A named version saved; after a forced browser reload, both fixtures retained their dimensions, coordinates and sizing settings. The reload tool timed out after 10 seconds, but subsequent browser navigation records confirmed completion and a fresh API read matched the saved state.
Scope and limits. Only simple rectangles in single-layer layouts were tested through the official plugin API, not manual GUI operations. A separate simple English dynamic text test is described below. Pending: broader font wrapping, more complex nested layouts, grid, minimum/maximum sizes, complex hug/fill combinations, production responsive behavior and Figma migration. The earlier fixed-height 240-unit fixture still needed 244 units for its padding; this separate automatic-height test does not change that result. The native API .penpot backup export failure remains unresolved; cloud saving is not a local backup.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Official plugin API · Original English text, one font, single-layer layout
A 360-wide vertical flex container used 20-unit padding and a 12-unit gap. Native text used sourcesanspro, font size 16, line height 1.5, auto-height and fill width, followed by an 80×24 rectangle. Replacing a short sentence with an original paragraph increased text height from 24 to 96 and container height from 100 to 172; the following rectangle moved from y=56 to y=128. At container width 220, text width became approximately 180 and height 192, moving the rectangle to y=224. These measurements support text reflow; individual line breaks and glyph fidelity were not checked.
Scope and limits. Resize limitation: calling resize(220, currentHeight) explicitly supplied both dimensions and changed container verticalSizing from auto to fix. Its height stayed 172 while the following rectangle ended at 248, outside the container. Restoring width 360 and the short sentence did not restore automatic height; a saved version and forced reload retained that fixed-height state. Explicitly setting verticalSizing back to auto restored height 100 for the short sentence. With the narrow long paragraph and auto explicitly restored, container height became 268, including 20 units below the rectangle; a second saved version and forced reload retained it. This is an observation of that plugin API sequence, not proof that manual GUI resizing behaves identically or a verdict that the product is defective. Pending: Chinese and RTL text, rich text, multiple or missing fonts, long unbroken words, more complex nested layouts, grid, manual GUI workflows, migration and performance. Native API backup export remains unresolved; cloud saving is not a local backup.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Official plugin API · Two nested vertical flex containers, original rectangles
The outer container used 20-unit padding and a 16-unit gap. Its inner container used 12-unit padding, an 8-unit gap, fill width and automatic height, with two fill-width rectangles of heights 40 and 60. An 80×24 footer followed the inner container. Reducing outer width from 400 to 280 changed inner width from 360 to 240 and rectangle widths from 336 to 216. Increasing the second rectangle height from 60 to 100 increased inner height from 132 to 172 and outer height from 212 to 252; the footer moved from y=168 to y=208. Restoring the dimensions and sizing settings restored the original layout. A saved version and forced browser reload retained the recorded coordinates, sizing settings, object IDs and parent relationships.
Scope and limits. Explicit mode restoration was required: resize(280, currentHeight) changed the outer verticalSizing to fix, and resizing the rectangle changed its horizontalSizing to fix. The test explicitly restored outer auto height and rectangle fill width before checking propagation. It does not show that resize preserves auto/fill modes or establish manual GUI behavior. Simple nested dynamic text in English is covered separately below. Pending: broader text layouts, more than two levels, mixed directions, grid, minimum/maximum sizes, layouts within components, GUI workflows, Figma migration and performance. Only API coordinates and dimensions were checked, not pixel-level fidelity. Native API backup export remains unresolved; cloud saving is not a local backup.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · Official plugin API · Original English text, one font, two vertical flex levels
The outer container used 20-unit padding and a 16-unit gap; the inner container used 12-unit padding and an 8-unit gap. Native text used sourcesanspro, size 16, line height 1.5, fill width and auto-height, followed by an 80×24 inner marker. An 80×24 footer followed the inner container. At outer width 400, replacing a short sentence with a paragraph increased text height from 24 to 96, inner height from 80 to 152 and outer height from 160 to 232. At outer width 280, text width was 216 and height 144; inner height was 200 and outer height 280. The inner marker and outer footer moved to y=184 and y=236. Restoring the short sentence reduced text height to 24, inner height to 80 and outer height to 160. Restoring width 400, saving a named version and forcing a browser reload retained the original recorded dimensions, positions, sizing settings and parent relationships.
Scope and limits. Explicit auto restoration is a prerequisite: resizing the outer container changed its verticalSizing to fix. The test explicitly restored verticalSizing to auto before recording the narrow and restored layouts. This does not demonstrate that resize preserves automatic sizing. Only API coordinates and dimensions were checked; individual line breaks, glyph fidelity and pixel-level appearance were not verified. Pending: multiple fonts, Chinese or RTL text, more than two levels, mixed directions, grid, complex components, manual GUI workflows, Figma migration and performance. The earlier native API backup export failure remains unresolved; successful cloud saving is not a local backup.
The first export measured 1100×600 because the cloned component main instance remained inside the imported group and extended its bounds. Moving it to the page root restored 800×600 exports. This was a test setup correction, not evidence of an export-size bug. PNG decoding, dimensions and sampled colors were checked independently; the final PNG was inspected visually. Pixel-identical round-trip fidelity was not tested.
Plugin API export still fails: both currentFile.export('penpot') and the explicit include-libraries variant returned “No matching clause:” on retest. GUI success does not resolve this API failure. The initial API experiment obtained no native backup; the separate GUI result below supersedes that earlier lack of a local file.
Tested 2026-11-12 · Penpot 2.19.1 official cloud · GUI download and owner-assisted GUI import · API verification of the imported copy
The GUI downloaded a 93,430-byte .penpot file from our existing synthetic design. SHA256 and ZIP CRC checks passed. Browser automation refused local-file access, so the owner selected the downloaded file in the GUI import dialog. Penpot reported one successful import. The imported copy had a different file ID; the original was not overwritten. We compared 7 pages and 56 objects, including page roots, against the archive: page names and IDs, object ID sets, names, mapped types, and x/y/width/height. Archive frame, rect and circle types were mapped to API board, rectangle and ellipse names; one path used its stored bounding rectangle for geometry. A forced browser reload retained all recorded copy fields, and file validation reported no errors.
Scope and limits. This is a bounded GUI native-file round trip, not a completely lossless result. We did not verify every property, font, fill, component relationship or behavior, interaction, library, version history, pixel-level appearance, cross-version compatibility or offline self-hosted recovery. Native text characters matched between the two imported-copy reads; full rich-text structures were not compared with the archive. Plugin API export still fails with No matching clause, including with include-libraries. This test does not establish Figma migration compatibility or complete manual GUI usability.
Pending: a full workflow comparison. The separate 10-object migration check supports only its recorded text, component and fixed-layout cases; it does not establish complex-file compatibility or suitability for a production design team.
Official documentation checked 2026-11-12 · Not an installation test
Penpot can be used in a browser at design.penpot.app or on a self-hosted server. The official guide recommends current Chrome or Firefox and also lists WebKit support. This is browser access, not a native desktop installer. Penpot cloud and self-hosting guide ↗
The official first-steps guide links to migration instructions. Availability of a migration guide does not establish how well your files, components or layouts will transfer; that still requires testing. Penpot first steps and migration guidance ↗
Use the official Penpot cloud service in a supported browser, sign in, and create a separate draft for evaluation. Our test used the official cloud on Windows. Local desktop installation and self-hosted setup were not tested.
Use the official Penpot cloud service in a supported browser, sign in, and create a separate draft for evaluation. Our test used the official cloud on Windows. Local desktop installation and self-hosted setup were not tested.
Use the official Penpot cloud service in a supported browser, sign in, and create a separate draft for evaluation. Our test used the official cloud on Windows. Local desktop installation and self-hosted setup were not tested.
Our self-authored, one-page Figma file migrated through Penpot Exporter 0.26.3 to a .penpot archive, then through Penpot GUI import into a separate file. All 10 non-root objects were present, including two editable text layers, a linked rectangle component and one fixed layout row. Text dimensions differed by 1–3 pixels; complex files, libraries and other fonts remain untested. This is a converted archive, not direct .fig import. A separate server-side PNG preview export timed out after import. The earlier SVG/API experiment had different limits: imported text stayed svg-raw and the inner group was flattened. Neither small test proves general migration compatibility.
In the same file, a single-rectangle main component and two instances were tested through the official plugin API for fill color only. Both followed a main-color change. After one instance received an override, it kept that color during another main update and browser reload. Reset restored the main color and subsequent updates; a second reload preserved the result. Pending: cross-file shared libraries, nested components, variants, other properties, manual GUI component operations and complex Figma component migration. A separate Figma-to-Penpot import retained one linked rectangle component; its single fill change propagated through the plugin API. This was not a shared-component workflow test; no propagation latency was measured.
Pending: multiplayer editing, comments, sharing permissions and team workflows were not tested. The recorded experiment used a dedicated cloud draft; it provides no collaboration verdict.
Pending: self-hosted setup, configuration and operation were not tested. Our experiment used the official cloud service only. Consult the official cloud and self-hosting guide linked in the getting-started section; cloud test results do not validate a self-hosted installation.
A separate API test checked spacing, wrapping and direction with three fixed rectangles, including a fixed-height padding shortfall. Unverified checks include your actual files, fonts, component hierarchy, advanced layouts, prototypes and team workflow. GUI native backup export and owner-assisted GUI reimport succeeded for our synthetic file. The original remained separate. We checked 7 pages and 56 objects for page names/IDs, object IDs/names, mapped types and geometry; the imported-copy readings matched after reload. This is not a completely lossless result: full attributes, fonts, visual fidelity, component behavior, libraries, version history and cross-version recovery remain unverified. Plugin API export still fails with No matching clause, both with the default call and include-libraries. GUI success does not repair that API path. That backup experiment does not establish Figma migration compatibility; the separate 10-object Figma conversion above has its own recorded scope and limits.