Files
penpot/docs/technical-guide/developer/devenv.md
2026-03-17 11:49:14 +01:00

8.9 KiB

title, desc
title desc
3.03. Dev environment Dive into Penpot's development environment. Learn about self-hosting, configuration, developer tools, architecture, and more. See the Penpot Technical Guide!

Development environment

System requirements

You need to have docker and docker-compose V2 installed on your system in order to correctly set up the development environment.

You can look here for complete instructions.

Optionally, to improve performance, you can also increase the maximum number of user files able to be watched for changes with inotify:

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

Getting Started

The interactive development environment requires some familiarity of tmux.

To start it, clone penpot repository, and execute:

./manage.sh pull-devenv
./manage.sh run-devenv

This will do the following:

  1. Pull the latest devenv image from dockerhub.
  2. Start all the containers in the background.
  3. Attach the terminal to the devenv container and execute the tmux session.
  4. The tmux session automatically starts all the necessary services.

This is an incomplete list of devenv related subcommands found on manage.sh script:

./manage.sh build-devenv-local # builds the local devenv docker image (called by run-devenv automatically when needed)
./manage.sh start-devenv       # starts background running containers
./manage.sh run-devenv         # enters to new tmux session inside of one of the running containers
./manage.sh stop-devenv        # stops background running containers
./manage.sh drop-devenv        # removes all the containers, volumes and networks used by the devenv

Having the container running and tmux opened inside the container, you are free to execute commands and open as many shells as you want.

You can create a new shell just pressing the Ctr+b c shortcut. And Ctrl+b w for switch between windows, Ctrl+b & for kill the current window.

For more info: https://tmuxcheatsheet.com/

It may take a minute or so, but once all of the services have started, you can connect to penpot by browsing to http://localhost:3449 .

Frontend

The frontend build process is located on the tmux window 0 and window 1. On window 0 we have the gulp process responsible for watching and building styles, fonts, icon-spreads and templates.

On window 1 we can find the shadow-cljs process that is responsible for watching and building frontend clojurescript code.

In addition to the watch process you probably want to be able to open a REPL process on the frontend application. In order to do this you can split the window (Ctrl+b ") and execute:

cd penpot/frontend
npx shadow-cljs cljs-repl main

In order to have the REPL working you need to have an active browser session with the penpot application opened (otherwise, you will get the error No application has connected to the REPL server.).

Finally, in case you want to connect to the REPL from your IDE, you can set it up to use nREPL with the port 3447 and the host localhost (you can see the port in the startup message of the shadow-cljs process in window 1). You will also need to call (shadow/repl :main) in the REPL to start the connection, as explained here.

Storybook

The storybook local server is started on tmux window 2 and will listen for changes in the styles, components or stories defined in the folders under the design system namespace: app.main.ui.ds.

You can open the broser on http://localhost:6006/ to see it.

For more information about storybook check:

https://help.penpot.app/technical-guide/developer/ui/#storybook

Exporter

The exporter build process is located in the window 3 and in the same way as frontend application, it is built and watched using shadow-cljs.

The main difference is that exporter will be executed in a nodejs, on the server side instead of browser.

The window is split into two slices. The top slice shows the build process and on the bottom slice has a shell ready to execute the generated bundle.

You can start the exporter process executing:

node target/app.js

This process does not start automatically.

Backend

The backend related process is located in the tmux window 4, and you can go directly to it using ctrl+b 4 shortcut.

By default the backend will be started in a non-interactive mode for convenience but you can press Ctrl+c to exit and execute the following to start the repl:

./scripts/repl

On the REPL you have these helper functions:

  • (start): start all the environment
  • (stop): stops the environment
  • (restart): stops, reload and start again.

And many other that are defined in the dev/user.clj file.

If an exception is raised or an error occurs when code is reloaded, just use (repl/refresh-all) to finish loading the code correctly and then use (restart) again.

Email

To test email sending, the devenv includes MailCatcher, a SMTP server that is used for develop. It does not send any mail outbounds. Instead, it stores them in memory and allows to browse them via a web interface similar to a webmail client. Simply navigate to:

http://localhost:1080

Create user

You can register a new user manually, or create new users automatically with this script. From your tmux instance, run:

cd penpot/backend/scripts
python3 manage.py create-profile

You can also skip tutorial and walkthrough steps:

python3 manage.py create-profile --skip-tutorial --skip-walkthrough
python3 manage.py create-profile -n "Jane Doe" -e jane@example.com -p secretpassword --skip-tutorial --skip-walkthrough

Feature Flags

Frontend flags via config.js

You can enable or disable feature flags on the frontend by creating (or editing) a config.js file at frontend/resources/public/js/config.js. This file is gitignored, so it has to be created manually. Your local flags won't affect other developers.

Set the penpotFlags variable with a space-separated list of flags:

var penpotFlags = "enable-mcp enable-webhooks enable-access-tokens";

Each flag entry uses the format enable-<flag> or disable-<flag>. They are merged on top of the built-in defaults, so you only need to list the flags you want to change.

Some examples of commonly used flags:

  • enable-access-tokens — enables the Access Tokens section under profile settings.
  • enable-mcp — enables the MCP server configuration section.
  • enable-webhooks — enables webhooks configuration.
  • enable-login-with-ldap — enables LDAP login.

The full list of available flags can be found in common/src/app/common/flags.cljc.

After creating or modifying this file, reload the browser (no need to restart anything).

Backend flags via PENPOT_FLAGS

Backend feature flags are controlled through the PENPOT_FLAGS environment variable using the same enable-<flag> / disable-<flag> format. You can set this in the docker/devenv/docker-compose.yaml file under the main service environment section:

environment:
  - PENPOT_FLAGS=enable-access-tokens enable-mcp

This requires restarting the backend to take effect.

Note

: Some features (e.g., access tokens, webhooks) need both frontend and backend flags enabled to work end-to-end. The frontend flag enables the UI, while the backend flag enables the corresponding API endpoints.

Team Feature Flags

To test a Feature Flag, you can enable or disable them by team through the dbg page:

  1. Create a new team or navigate to an existing team in Penpot.
  2. Copy the team-id from the URL (e.g., ?team-id=1234bd95-69dd-805c-8005-c015415436ae). If no team is selected, the default profile team will be used.
  3. Go to http://localhost:3449/dbg.
  4. Open the Feature Flag panel, enter the team-id and the feature name in either the enable or disable section, and click Submit.