Skip to content
Johann Pardanaud

Running Electron on Heroku

These last days I've developed a module to scrap some data with Nightmare, a headless browser based on Electron. Once my code was finished I tried to run it on Heroku's infrastructure and was pretty disappointed to see it wasn't running though it worked perfectly on my local machine.

After a bit of research, I've found that “Electron requires a display driver to function”. Of course, Heroku doesn't provide any display driver since there is nearly no incentive to that. Thankfully, the Electron team addressed this issue (on the same documentation page) and recommends to use Xvfb, a tool which allows to run a virtual display server on your machine.

Installing Xvfb

You will need to add the APT buildpack to your app, which allows to install APT packages at compile time:

heroku buildpacks:add -i 1 https://github.com/heroku/heroku-buildpack-apt

Then add a file named Aptfile in the root directory of your app with the following contents, each line contains the name of a package we want to install:

libxss1
xvfb

The next time you will deploy your application, Xvfb will be installed on your dynos, however the command will not work right out of the box because of the architecture of Heroku's servers. You will need to install the Xvfb buildpack written by yoz, which patches the Xvfb command so it can run properly. Obviously, this buildpack should run after the APT one:

heroku buildpacks:add -i 2 https://github.com/captain401/heroku-buildpack-xvfb

Running the virtual display server

Now you need to run Xvfb before launching your Electron process. Instead of starting a new instance of Xvfb each time you want to run Electron, you could launch Xvfb at startup. Heroku provides the ability to run a bash script on startup through a .profile file located at the root directory of your app. Here is what it should contain:

export DISPLAY=':99.0'
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &

These two lines are copied from the configuration the Electron team provides for Travis CI. The $DISPLAY variable identifies your Xvfb instance and will be read by Electron, according to the documentation:

Chromium in Electron will automatically look for $DISPLAY, so no further configuration of your app is required.

In the second line we run the Xvfb server in background and define the screen properties.

One last thing, maybe you want to run the virtual display server only on one type of dyno. Heroku provides a $DYNO variable containing the process type and an identifier. So if you want to run Xvfb only for the scraper process type, you will need to write the following code in your .profile file:

if [ -z "$DYNO" ] || [[ $DYNO == *"scraper"* ]]; then
    export DISPLAY=':99.0'
    Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
fi

The [ -z "$DYNO"] part checks if the variable is unset or empty. I prefer to add this since Heroku states in its documentation:

The $DYNO variable is experimental and subject to change or removal.

Thus, if the $DYNO variable gets removed, your virtual display server will still be running, but on all your dynos instead on the type you defined.

It might be simpler in the future

Since December, Chromium supports the --headless command line flag which allows to run it without any display server. I don't know if Electron will integrate this feature in the future, but this could be great for saving time for developers.

I'm Johann Pardanaud, a freelance Back-End developer available to work on your projects! I can help you architect and code your projects by taking advantage of microservices, thoughtful database structures, and asynchronous flows.