We use cookies to enhance your experience on the site
CodeWorlds
Back to collections
Guide21 min read

Penpot, an open source interface design tool

Penpot is an open source interface design tool you can self host. Cloud pricing, the file format, and an honest comparison with Figma.

Penpot, an open source interface design tool

Penpot is a browser based interface design tool whose source is open and which can run on your own server. It is developed by the Spanish company Kaleidos under the Mozilla Public License 2.0, and the repository carries over fifty eight thousand stars. The current release is 2.17.0, dated 22 July 2026.

Who this is really for

The honest answer: for teams to whom control over their data matters, not for those seeking a tool better than Figma at design work itself.

The case for this platform is clearest in three situations. The first is an organisation where designs cannot sit on somebody else's server, meaning the public sector, healthcare, defence. Running it on your own infrastructure solves a problem no closed product will solve, because none offers that option.

The second is reluctance to depend on a single vendor. Designs stored in a closed format are hostage to a vendor's pricing decisions, and the industry's experience in recent years taught many teams caution. Here files rest on open formats and can be opened outside the application itself.

The third is cost at a large team, but only in the self hosted variant. In the cloud, as you will see shortly, the free plan has limits.

If, on the other hand, you are looking for a tool where design work moves faster than in commercial products, this is not it. Penpot has closed the gap on fundamentals, but the plugin ecosystem, animation maturity, and the small conveniences of daily work still sit on the other side. This choice is made for strategic reasons rather than for comfort.

Pricing, a correction

This needs putting right, because a belief has taken hold online that Penpot is entirely free with no limits, and an earlier version of this text repeated it. The source is open and self hosting genuinely costs nothing beyond infrastructure. The cloud service, however, has plans.

Cloud planPriceScope
Professional0 USDup to 8 team members, 10 GB storage, 7 days of version history
Unlimited7 USD per user per month25 GB storage, 30 days of history, bill capped at 175 USD per month
Enterprise25 USD per user per monthunlimited storage, 90 days of history, admin console, single sign on, audit logs, from 950 USD per month
Private server50,000 USD per yeardedicated infrastructure, region choice, guaranteed response times

The eight person limit on the free plan is what most teams run into, since viewers are unlimited but designers are not. Before pricing a team at the full rate, though, check the discounts for non profits, education, and open source projects, which the vendor runs outside the price list and which you have to ask for. The cap on the paid plan at a hundred and seventy five dollars a month is also worth noting: past twenty five people the per person price starts falling, which is rare in this category.

The self hosted variant carries no licence fees. It is worth costing honestly, though, adding the server, backups, upgrades, and the time of whoever maintains it. For an eight person team the free cloud plan works out cheaper than a self hosted instance counted with labour.

The file format and what follows from it

The no lock in argument appears in every piece written about this tool, so it is worth qualifying, because it tends to be presented too optimistically.

It is true that shapes and graphics rest on open standards, so a single screen exported to a vector file opens in any graphics application. That is a genuine advantage over binary formats readable by nothing but the vendor's own software.

It is not true that an entire project is portable. Components, libraries, prototype interactions, and dependencies between files are structures specific to this application. Opening an export elsewhere gives you graphics, not a working design system with its relationships intact.

The practical conclusion is that openness protects you against losing access to content rather than against the cost of migration. That is still more than most competitors offer, but it is worth knowing exactly what you are counting on.

There is a second side to that openness, mentioned less often and useful day to day. Since the graphics rest on web standards, export goes straight to a format you drop into a page, with no intermediate conversion step. On icons and simple illustrations that removes a little friction between design and implementation, since the developer receives a file ready to use rather than something that first has to pass through an export tool.

Do bear in mind, though, that files leaving design tools are rarely optimised. They carry metadata, excess coordinate precision, and groups adding nothing, so before deployment they pass through an optimiser anyway. That is a small thing, but it returns on every project, and setting it up once in the build process beats doing it by hand for every icon.

Why Penpot?

Key advantages

  1. Open source - Repository publicly available under the Mozilla Public License 2.0
  2. Self hosting - Can run on your own infrastructure with no licence fees
  3. Browser based - Works in any browser without installation
  4. Open formats - Graphics built on standards rather than a binary format
  5. Real time collaboration - Several people in one file
  6. Platform independence - Windows, macOS, and Linux through a browser
  7. Data control - With a self hosted instance, data never leaves the organisation

Penpot vs Figma vs Sketch vs Adobe XD

FeaturePenpotFigmaSketchAdobe XD
Pricefree up to 8 people, then from 7 USDfree tier plus subscriptionsubscriptionproduct discontinued
Open sourceyes, MPL 2.0nonono
Self hostingyesnonono
Runs in a browseryesyesno, macOS onlyno
Open graphics formatyesexport onlyexport onlyexport only
Pluginsfewa great manymanydiscontinued
Flexible layoutsyes, built on the CSS modelyesyesnot applicable
Works offlineyes, on your own servernoyesyes

Installation and getting started

Option 1: Penpot Cloud (fastest)

Code
Bash
# Just go to the website
https://design.penpot.app

# Register a free account
# Done - you can start designing!

Option 2: Self-hosting with Docker

Code
Bash
# Clone the official repository
git clone https://github.com/penpot/penpot.git
cd penpot/docker/images

# Start using Docker Compose
docker-compose -f docker-compose.yaml up -d

# Penpot will be available at
# http://localhost:9001

Docker Compose configuration

docker-compose.yaml
YAML
# docker-compose.yaml
version: "3.5"

services:
  penpot-frontend:
    image: "penpotapp/frontend:latest"
    restart: always
    ports:
      - 9001:80
    volumes:
      - penpot_assets_data:/opt/data/assets
    depends_on:
      - penpot-backend
      - penpot-exporter
    environment:
      - PENPOT_FLAGS=enable-registration enable-login-with-password

  penpot-backend:
    image: "penpotapp/backend:latest"
    restart: always
    volumes:
      - penpot_assets_data:/opt/data/assets
    depends_on:
      - penpot-postgres
      - penpot-redis
    environment:
      - PENPOT_FLAGS=enable-registration enable-login-with-password disable-email-verification
      - PENPOT_PUBLIC_URI=http://localhost:9001
      - PENPOT_DATABASE_URI=postgresql://penpot-postgres/penpot
      - PENPOT_DATABASE_USERNAME=penpot
      - PENPOT_DATABASE_PASSWORD=penpot
      - PENPOT_REDIS_URI=redis://penpot-redis/0
      - PENPOT_ASSETS_STORAGE_BACKEND=assets-fs
      - PENPOT_STORAGE_ASSETS_FS_DIRECTORY=/opt/data/assets

  penpot-exporter:
    image: "penpotapp/exporter:latest"
    restart: always
    environment:
      - PENPOT_PUBLIC_URI=http://penpot-frontend

  penpot-postgres:
    image: "postgres:15"
    restart: always
    stop_signal: SIGINT
    volumes:
      - penpot_postgres_v15:/var/lib/postgresql/data
    environment:
      - POSTGRES_INITDB_ARGS=--data-checksums
      - POSTGRES_DB=penpot
      - POSTGRES_USER=penpot
      - POSTGRES_PASSWORD=penpot

  penpot-redis:
    image: redis:7
    restart: always

volumes:
  penpot_postgres_v15:
  penpot_assets_data:

Option 3: installation on Kubernetes

penpot-deployment.yaml
YAML
# penpot-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: penpot
  namespace: design-tools
spec:
  replicas: 1
  selector:
    matchLabels:
      app: penpot
  template:
    metadata:
      labels:
        app: penpot
    spec:
      containers:
      - name: penpot-frontend
        image: penpotapp/frontend:latest
        ports:
        - containerPort: 80
        env:
        - name: PENPOT_FLAGS
          value: "enable-registration enable-login-with-password"
      - name: penpot-backend
        image: penpotapp/backend:latest
        env:
        - name: PENPOT_PUBLIC_URI
          value: "https://penpot.yourdomain.com"
        - name: PENPOT_DATABASE_URI
          valueFrom:
            secretKeyRef:
              name: penpot-secrets
              key: database-uri
---
apiVersion: v1
kind: Service
metadata:
  name: penpot-service
  namespace: design-tools
spec:
  selector:
    app: penpot
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer

Main Penpot features

1. Vector editing tools

Code
TEXT
Penpot offers a full set of vector tools:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Shape Tools                                      β”‚
β”‚  β”œβ”€β”€ Rectangle (R)                                   β”‚
β”‚  β”œβ”€β”€ Ellipse (E)                                     β”‚
β”‚  β”œβ”€β”€ Polygon                                         β”‚
β”‚  └── Star                                            β”‚
β”‚                                                      β”‚
β”‚  Drawing Tools                                    β”‚
β”‚  β”œβ”€β”€ Pen Tool (P) - Bezier curves                   β”‚
β”‚  β”œβ”€β”€ Pencil Tool - Freehand drawing                 β”‚
β”‚  └── Path editing                                    β”‚
β”‚                                                      β”‚
β”‚  Boolean Operations                               β”‚
β”‚  β”œβ”€β”€ Union - Merge shapes                           β”‚
β”‚  β”œβ”€β”€ Difference - Subtract                          β”‚
β”‚  β”œβ”€β”€ Intersection - Common area                     β”‚
β”‚  └── Exclusion - Exclude overlap                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Flex Layout (auto-layout)

Penpot introduces Flex Layout inspired by CSS Flexbox:

Code
CSS
/* CSS equivalent of Penpot Flex Layout */
.flex-container {
  display: flex;
  flex-direction: row | column;
  justify-content: flex-start | center | flex-end | space-between | space-around;
  align-items: flex-start | center | flex-end | stretch;
  gap: 16px;
  padding: 24px;
}

/* In Penpot you set this through the UI:
   1. Select the container
   2. Design panel > Layout > Flex
   3. Set Direction, Alignment, Gap, Padding
*/

Practical example:

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CARD COMPONENT with Flex Layout                    β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  [Image]                                       β”‚  β”‚
β”‚  β”‚                                                β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ Title                          [Icon]   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ Description text that can wrap to       β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ multiple lines automatically            β”‚  β”‚  β”‚
β”‚  β”‚  β”‚                                         β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ [Button]              [Button]          β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                      β”‚
β”‚  Flex structure:                                    β”‚
β”‚  - Main container: Column, gap: 16px               β”‚
β”‚  - Header: Row, space-between                       β”‚
β”‚  - Buttons: Row, gap: 8px, align-end               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3. Components and instances

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  COMPONENT SYSTEM                                    β”‚
β”‚                                                      β”‚
β”‚  1. Create Main Component:                          β”‚
β”‚     - Select elements                               β”‚
β”‚     - Ctrl/Cmd + K or right-click > Create Componentβ”‚
β”‚                                                      β”‚
β”‚  2. Use instances:                                  β”‚
β”‚     - Drag from Assets panel                        β”‚
β”‚     - Or Ctrl/Cmd + D to duplicate                  β”‚
β”‚                                                      β”‚
β”‚  3. Edit Main Component:                            β”‚
β”‚     - Changes propagate to all instances            β”‚
β”‚                                                      β”‚
β”‚  4. Override in instance:                           β”‚
β”‚     - You can override text, colors, images         β”‚
β”‚     - Reset override: right-click > Reset           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

4. Design Tokens and styles

Code
TEXT
/* Penpot supports global styles for: */

/* Colors */
--color-primary: #3366FF;
--color-secondary: #6B7280;
--color-success: #10B981;
--color-error: #EF4444;

/* Typography */
--font-heading: Inter, 700, 32px;
--font-body: Inter, 400, 16px;
--font-caption: Inter, 400, 12px;

/* Shadows */
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1);

/* In Penpot:
   1. Design panel > Fill/Stroke > + Add to library
   2. Name the style
   3. Use in other elements via Assets panel
*/

5. Interactive prototyping

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PROTOTYPING INTERACTIONS                           β”‚
β”‚                                                      β”‚
β”‚  Available triggers:                                β”‚
β”‚  β”œβ”€β”€ On Click                                       β”‚
β”‚  β”œβ”€β”€ Mouse Enter (Hover)                            β”‚
β”‚  β”œβ”€β”€ Mouse Leave                                    β”‚
β”‚  └── After Delay                                    β”‚
β”‚                                                      β”‚
β”‚  Available actions:                                 β”‚
β”‚  β”œβ”€β”€ Navigate To - go to another page               β”‚
β”‚  β”œβ”€β”€ Open Overlay - open popup/modal                β”‚
β”‚  β”œβ”€β”€ Close Overlay - close overlay                  β”‚
β”‚  β”œβ”€β”€ Previous Page - go back                        β”‚
β”‚  └── Open URL - open external link                  β”‚
β”‚                                                      β”‚
β”‚  Transition animations:                             β”‚
β”‚  β”œβ”€β”€ Dissolve - smooth fade                         β”‚
β”‚  β”œβ”€β”€ Slide - sliding motion                         β”‚
β”‚  β”‚   β”œβ”€β”€ Right, Left, Up, Down                      β”‚
β”‚  └── Push - pushing transition                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example of creating a prototype:

Code
TEXT
Scenario: Login Flow

[Login Screen] ──Click "Sign In"──> [Dashboard]
      β”‚
      └──Click "Forgot Password"──> [Reset Password]
                                          β”‚
                                    Click "Send"
                                          β”‚
                                          v
                                    [Confirmation Modal]
                                          β”‚
                                    After 3s / Click
                                          β”‚
                                          v
                                    [Login Screen]

6. Grid system and guides

Code
CSS
/* Penpot supports various grid types */

/* Layout Grid - for responsive design */
.layout-grid {
  columns: 12;
  gutter: 24px;
  margin: auto | fixed;
  type: stretch | center | left | right;
}

/* Square Grid - for pixel-perfect design */
.square-grid {
  size: 8px;
  color: rgba(0, 0, 0, 0.1);
}

/* Custom Guides */
.guides {
  horizontal: 64px, 128px, 512px;
  vertical: 50%, 100%;
}

7. Export options

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  EXPORT FORMATS                                      β”‚
β”‚                                                      β”‚
β”‚  Images:                                            β”‚
β”‚  β”œβ”€β”€ PNG - with transparency                        β”‚
β”‚  β”œβ”€β”€ JPEG - for photos                              β”‚
β”‚  β”œβ”€β”€ SVG - vectors (native format!)                 β”‚
β”‚  └── PDF - for documentation                        β”‚
β”‚                                                      β”‚
β”‚  Scale options:                                      β”‚
β”‚  β”œβ”€β”€ 1x - standard                                  β”‚
β”‚  β”œβ”€β”€ 2x - retina                                    β”‚
β”‚  β”œβ”€β”€ 3x - high DPI                                  β”‚
β”‚  └── Custom - e.g. 0.5x, 4x                         β”‚
β”‚                                                      β”‚
β”‚  Full project export:                               β”‚
β”‚  - File > Export project (.penpot)                  β”‚
β”‚  - Includes all pages, components, assets           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

CSS code generation

Penpot automatically generates CSS code for selected elements:

Code
CSS
/* Example of generated CSS for a button */
.button {
  /* Layout */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  gap: 8px;

  /* Appearance */
  background: #3366FF;
  border-radius: 8px;

  /* Typography */
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: 16px;
  line-height: 24px;
  color: #FFFFFF;

  /* Effects */
  box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
}

/* Hover state (from prototype) */
.button:hover {
  background: #2952CC;
  transform: translateY(-1px);
  box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.15);
}

Inspect panel - code generation

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  INSPECT MODE                                        β”‚
β”‚                                                      β”‚
β”‚  1. Enable Inspect mode (code icon in toolbar)      β”‚
β”‚  2. Click any element                               β”‚
β”‚  3. View the generated code:                        β”‚
β”‚                                                      β”‚
β”‚  Tabs:                                              β”‚
β”‚  β”œβ”€β”€ Info - dimensions, position                    β”‚
β”‚  β”œβ”€β”€ Design - CSS styles                            β”‚
β”‚  └── Code - full CSS/SVG                            β”‚
β”‚                                                      β”‚
β”‚  Copying:                                           β”‚
β”‚  - Click to copy individual properties              β”‚
β”‚  - "Copy all" for full CSS                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Team collaboration

Real-time collaboration

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  COLLABORATION FEATURES                              β”‚
β”‚                                                      β”‚
β”‚  Multi-cursor editing                            β”‚
β”‚  β”œβ”€β”€ See other users' cursors                       β”‚
β”‚  β”œβ”€β”€ Colored avatars next to selections             β”‚
β”‚  └── Live preview of changes                        β”‚
β”‚                                                      β”‚
β”‚  Comments                                        β”‚
β”‚  β”œβ”€β”€ Click anywhere + C to add comment              β”‚
β”‚  β”œβ”€β”€ Thread replies                                 β”‚
β”‚  β”œβ”€β”€ Resolve/Unresolve                              β”‚
β”‚  └── Mentions @username                             β”‚
β”‚                                                      β”‚
β”‚  Sharing                                         β”‚
β”‚  β”œβ”€β”€ View link - view only                          β”‚
β”‚  β”œβ”€β”€ Edit link - full editing                       β”‚
β”‚  └── Prototype link - interactive prototype         β”‚
β”‚                                                      β”‚
β”‚  Team Libraries                                  β”‚
β”‚  β”œβ”€β”€ Shared components                              β”‚
β”‚  β”œβ”€β”€ Shared styles (colors, typography)             β”‚
β”‚  └── Sync across projects                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Version history

Code
TEXT
Version history in Penpot:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  FILE > Version History                              β”‚
β”‚                                                      β”‚
β”‚  Today                                           β”‚
β”‚  β”œβ”€β”€ 14:32 - Jan updated Button component           β”‚
β”‚  β”œβ”€β”€ 13:15 - Maria added new page                   β”‚
β”‚  └── 11:00 - Auto-save                              β”‚
β”‚                                                      β”‚
β”‚  Yesterday                                       β”‚
β”‚  β”œβ”€β”€ 18:45 - Jan renamed project                    β”‚
β”‚  └── 09:30 - Initial version                        β”‚
β”‚                                                      β”‚
β”‚  Actions:                                           β”‚
β”‚  - Preview any version                              β”‚
β”‚  - Restore to previous version                      β”‚
β”‚  - Create named snapshot                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Plugins and extensions

Penpot is actively developing its plugin system:

Available plugins (2024+)

Code
TypeScript
// Example Penpot plugin structure
// penpot-plugin-example/manifest.json
{
  "name": "My Penpot Plugin",
  "version": "1.0.0",
  "description": "Example plugin for Penpot",
  "main": "index.js",
  "permissions": [
    "selection:read",
    "selection:write",
    "file:read",
    "file:write"
  ]
}

// penpot-plugin-example/index.js
penpot.ui.open("My Plugin", `
  <div style="padding: 16px;">
    <h2>My Plugin</h2>
    <button onclick="applyColors()">Apply Brand Colors</button>
  </div>
`);

async function applyColors() {
  const selection = await penpot.selection.get();

  for (const shape of selection) {
    await penpot.shape.update(shape.id, {
      fill: { color: "#3366FF" }
    });
  }
}

Plugin ideas

Code
TEXT
Popular plugin types:
β”œβ”€β”€ Content generators (Lorem ipsum, avatars, data)
β”œβ”€β”€ Design tokens import/export
β”œβ”€β”€ Accessibility checkers
β”œβ”€β”€ Icon libraries
β”œβ”€β”€ Chart generators
β”œβ”€β”€ Code export (Tailwind, CSS-in-JS)
β”œβ”€β”€ Design system documentation
└── Integration with dev tools

Integrations

Git integration

Code
Bash
# Export project to SVG and version with Git
penpot-cli export --project "My Project" --format svg --output ./designs

# File structure
designs/
β”œβ”€β”€ page-1/
β”‚   β”œβ”€β”€ frame-login.svg
β”‚   β”œβ”€β”€ frame-dashboard.svg
β”‚   └── components/
β”‚       β”œβ”€β”€ button.svg
β”‚       └── card.svg
β”œβ”€β”€ page-2/
β”‚   └── ...
└── tokens.json

Webhooks

Code
JavaScript
// Webhook configuration (self-hosted)
// config.edn
{:webhooks
 {:events #{:file-change :comment-created :member-joined}
  :url "https://your-server.com/penpot-webhook"
  :secret "your-webhook-secret"}}

// Webhook handler
app.post('/penpot-webhook', (req, res) => {
  const { event, payload } = req.body;

  switch (event) {
    case 'file-change':
      console.log(`File ${payload.file_id} was modified`);
      // Trigger CI/CD pipeline
      break;
    case 'comment-created':
      // Notify on Slack
      break;
  }

  res.status(200).send('OK');
});

API access (self-hosted)

Code
Python
# Python SDK for Penpot API
import requests

class PenpotAPI:
    def __init__(self, base_url, token):
        self.base_url = base_url
        self.headers = {"Authorization": f"Bearer {token}"}

    def get_projects(self):
        response = requests.get(
            f"{self.base_url}/api/rpc/command/get-all-projects",
            headers=self.headers
        )
        return response.json()

    def export_file(self, file_id, format="svg"):
        response = requests.post(
            f"{self.base_url}/api/export",
            headers=self.headers,
            json={
                "file_id": file_id,
                "format": format,
                "scale": 1
            }
        )
        return response.content

# Usage
api = PenpotAPI("https://your-penpot.com", "your-api-token")
projects = api.get_projects()
svg_data = api.export_file("file-uuid", "svg")

Design system in Penpot

Creating a design system

Code
TEXT
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  DESIGN SYSTEM STRUCTURE                             β”‚
β”‚                                                      β”‚
β”‚  Design System Project                           β”‚
β”‚  β”œβ”€β”€ Foundations                                 β”‚
β”‚  β”‚   β”œβ”€β”€ Colors                                     β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Primary palette                        β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Neutral palette                        β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Semantic colors                        β”‚
β”‚  β”‚   β”‚   └── Gradients                              β”‚
β”‚  β”‚   β”œβ”€β”€ Typography                                 β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Headings (H1-H6)                       β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Body text                              β”‚
β”‚  β”‚   β”‚   └── UI text                                β”‚
β”‚  β”‚   β”œβ”€β”€ Spacing                                    β”‚
β”‚  β”‚   β”‚   └── 4px, 8px, 12px, 16px, 24px, 32px...   β”‚
β”‚  β”‚   β”œβ”€β”€ Shadows                                    β”‚
β”‚  β”‚   └── Border radius                              β”‚
β”‚  β”‚                                                   β”‚
β”‚  β”œβ”€β”€ Components                                  β”‚
β”‚  β”‚   β”œβ”€β”€ Buttons                                    β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Primary / Secondary / Ghost           β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ Small / Medium / Large                β”‚
β”‚  β”‚   β”‚   └── States: Default, Hover, Active, Disabledβ”‚
β”‚  β”‚   β”œβ”€β”€ Inputs                                     β”‚
β”‚  β”‚   β”œβ”€β”€ Cards                                      β”‚
β”‚  β”‚   β”œβ”€β”€ Navigation                                 β”‚
β”‚  β”‚   └── Modals                                     β”‚
β”‚  β”‚                                                   β”‚
β”‚  └── Patterns                                    β”‚
β”‚      β”œβ”€β”€ Forms                                      β”‚
β”‚      β”œβ”€β”€ Tables                                     β”‚
β”‚      └── Page layouts                               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Shared libraries

Code
TEXT
Sharing a Design System across projects:

1. Publish the library:
   File > Publish as Shared Library

2. Use in another project:
   Assets Panel > Libraries > + Add library

3. Synchronization:
   - Make changes in the source library
   - Assets Panel > Update available
   - Review changes > Update

Keyboard shortcuts

Essential shortcuts

ActionShortcut
Move toolV
RectangleR
EllipseE
FrameF
TextT
Pen toolP
CommentsC
Zoom in/outCmd/Ctrl + +/-
Zoom to fitCmd/Ctrl + 1
Zoom to selectionCmd/Ctrl + 2
PanSpace + drag
DuplicateCmd/Ctrl + D
GroupCmd/Ctrl + G
UngroupCmd/Ctrl + Shift + G
Create componentCmd/Ctrl + K
Copy/PasteCmd/Ctrl + C/V
Undo/RedoCmd/Ctrl + Z / Shift + Z
Hide/Show UICmd/Ctrl + \
Present prototypeCmd/Ctrl + Enter

Migrating from Figma to Penpot

Exporting from Figma

Code
TEXT
1. In Figma:
   - Select a frame or the entire page
   - File > Export
   - Choose SVG format
   - Check "Include 'id' attribute"

2. In Penpot:
   - File > Import
   - Select the exported SVG files
   - Adjust the imported elements

Migration limitations

Code
TEXT
What transfers well:
Vector shapes
Text (basic)
Colors and gradients
Effects (shadow, blur)
Grouping

What requires manual work:
Note: Auto-layout to Flex Layout (manual configuration)
Note: Components (need to be recreated)
Note: Prototyping (needs to be recreated)
Note: Plugins (no equivalents)
Note: Variants (in development in Penpot)

The import tool

Migration goes through an official plugin run on the Figma side, which packs a design into a file Penpot accepts. There is no command line tool doing the same, so the export step is performed by hand inside Figma.

Code
TEXT
1. Install the Penpot exporter plugin in Figma
2. Run it on the file you want to move
3. Download the generated .penpot file
4. In Penpot choose import and point at the downloaded file

The plugin's code sits in the penpot-exporter-figma-plugin repository, so before migrating a large project it pays to read the open issues and check whether any of them concerns the features you use.

What is missing against the competition

This section is usually skipped in articles like this, and it is the one that most helps a decision.

Plugins are the largest gap. The competition holds an ecosystem numbering in the thousands, from placeholder content generators to accessibility checkers. Penpot supports plugins, but their number is disproportionately smaller, and many daily conveniences have to be done by hand.

The second matter is prototyping. Basic transitions between screens work, while richer interactions, animated component states, and variable driven behaviour are thinner here. Enough to present a flow, not necessarily enough to show micro interactions to a client.

The third is performance on large files, as in other browser based tools such as Figma. The application runs in a browser, and a project with hundreds of screens can slow down more than is acceptable. Splitting work across several files helps and is a necessity here rather than a preference.

The fourth is availability of people who know the tool. Hiring a designer, you will find dozens of candidates working in commercial products and a handful who know this one. Learning the basics is quick, since the concepts are similar, but it is still a cost to count.

The fifth is handing designs outside your team. If you work with an agency or a client using a different tool, exchanging files becomes a problem. Import from competing formats exists but reconstructs graphics rather than components and prototypes, so part of the work has to be redone.

FAQ

Is Penpot really free?

The source is open, and self hosting carries no licence fees. The cloud service does have plans: the free one covers up to eight team members and ten gigabytes of storage, and past that you pay per person.

Can I work without network access?

Not in the cloud. With a self hosted instance yes, provided the server sits on your local network, since the application runs in a browser and needs to reach a server regardless.

Can I import designs from Figma?

Only partially. Graphics transfer through a vector format, but components, libraries, and prototypes have to be rebuilt by hand, since those are structures specific to each application.

Do plugins from competing tools work?

No. Penpot has its own plugin system and is not compatible with other programs' extensions. The number of available add ons is also markedly smaller than the competition's.

When does self hosting beat the cloud?

Usually only once the team exceeds the free plan's limit and you require that data not leave the organisation. For a small team without that requirement, the cost of maintaining a server exceeds the subscription saving.

Common deployment mistakes

The first is treating self hosting as a one off task. The application comprises several services, a database, and file storage, so upgrades, backups, and monitoring become somebody's responsibility. If nobody takes that on, six months later you are running a version with unpatched bugs.

The second is skipping backups of the file storage. The database alone is not enough, because images and assets sit separately, and restoring a project without them leaves empty frames where the graphics were.

The third is migrating the whole team at once. It is wiser to start with one project, check whether the missing features genuinely impede your work, and only then decide about the rest.

The fourth is keeping everything in one file. The application runs in a browser and slows on large projects, so splitting by topic is a practical necessity here rather than a matter of tidiness.

The fifth is assuming developer handoff looks the same as in the tool you came from. An inspection mode with specifications exists, but treat generated code as a reference for values rather than something to paste into a Tailwind CSS or React project.

The source and releases live in the Penpot repository, and current plans on the pricing page.