Skip to content

Getting Started

WARNING

GNOME Shell and Extensions use ESModules as of GNOME 45. Please see the Legacy Documentation for previous versions.

This page will guide you through setting up a basic development environment and creating a new extension. If this is your first extension, it is recommended that you use the gnome-extensions tool.

GNOME Extensions Tool

TIP

The gnome-extensions create command can be run from any directory, because it will always create the extension in ~/.local/share/gnome-shell/extensions.

GNOME Shell ships with a program you can use to create a skeleton extension by running gnome-extensions create.

Instead of passing options on the command line, you can start creating an extension interactively:

sh
$ gnome-extensions create --interactive
  1. Choose a name:

    no-line-numbers
    Name should be a very short (ideally descriptive) string.
    Examples are: “Click To Focus”, “Adblock”, “Shell Window Shrinker”
    Name: Example Extension
  2. Choose a description:

    no-line-numbers
    Description is a single-sentence explanation of what your extension does.
    Examples are: “Make windows visible on click”, “Block advertisement popups”, “Animate windows shrinking on minimize”
    Description: An example extension
  3. Choose a UUID for your extension:

    no-line-numbers
    UUID is a globally-unique identifier for your extension.
    This should be in the format of an email address (clicktofocus@janedoe.example.com)
    UUID: example@gjs.guide
  4. Choose the starting template:

    no-line-numbers
    Choose one of the available templates:
    1) Plain       –  An empty extension
    2) Indicator   –  Add an icon to the top bar
    Template [1-2]: 1

The whole process looks like this on the command line:

no-line-numbers
$ gnome-extensions create --interactive
Name should be a very short (ideally descriptive) string.
Examples are: “Click To Focus”, “Adblock”, “Shell Window Shrinker”
Name: Example Extension

Description is a single-sentence explanation of what your extension does.
Examples are: “Make windows visible on click”, “Block advertisement popups”, “Animate windows shrinking on minimize”
Description: An extension serving as an example

UUID is a globally-unique identifier for your extension.
This should be in the format of an email address (clicktofocus@janedoe.example.com)
UUID: example@gjs.guide

Choose one of the available templates:
1) Plain       –  An empty extension
2) Indicator   –  Add an icon to the top bar
Template [1-2]: 1

Once you finish the last step, the extension template will be created and opened in an editor.

Manual Creation

TIP

The directory name of the extension must match the UUID of the extension.

Start by creating an extension directory, and the two required files:

sh
$ mkdir -p ~/.local/share/gnome-shell/extensions/example@gjs.guide
$ cd ~/.local/share/gnome-shell/extensions/example@gjs.guide
$ touch extension.js metadata.json

Open extension.js and metadata.json with an IDE like GNOME Builder, or a simple editor like GNOME Text Editor, then populate them with the minimum requirements.

metadata.json

json
{
    "uuid": "example@gjs.guide",
    "name": "Example Extension",
    "description": "An example extension",
    "shell-version": [ "45" ],
    "url": "https://gjs.guide/extensions"
}

extension.js

js
import St from 'gi://St';

import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';


export default class ExampleExtension extends Extension {
    enable() {
        // Create a panel button
        this._indicator = new PanelMenu.Button(0.0, this.metadata.name, false);

        // Add an icon
        const icon = new St.Icon({
            icon_name: 'face-laugh-symbolic',
            style_class: 'system-status-icon',
        });
        this._indicator.add_child(icon);

        // Add the indicator to the panel
        Main.panel.addToStatusArea(this.uuid, this._indicator);
    }

    disable() {
        this._indicator?.destroy();
        this._indicator = null;
    }
}

Testing the Extension

TIP

For detailed information about loading and debugging GNOME Shell extensions, see the Debugging page.

Depending on whether you are running a Wayland session or an X11 session, we will prepare a simple debugging environment. For either session type, start by opening a new terminal, such as GNOME Terminal or GNOME Console.

Note that GNOME Shell will log many messages unrelated to your extension, and proper logging will help when developing your extension.

Wayland Sessions

Wayland sessions support running GNOME Shell in window, so an extension can be tested without disrupting the current session.

  1. Start a nested GNOME Shell session

    sh
    $ dbus-run-session -- gnome-shell --nested --wayland
  2. Open a terminal inside the new session and enable the extension

    sh
    $ gnome-extensions enable example@gjs.guide

X11 Sessions

X11 does not support running nested sessions, so we will restart GNOME Shell to load the extension and then enable it.

  1. Press Alt+F2 and run the built-in restart command

  2. Enable the extension

    sh
    $ gnome-extensions enable example@gjs.guide
  3. Monitor the output of GNOME Shell

    sh
    $ journalctl -f -o cat /usr/bin/gnome-shell

Loaded extensions are cached by the JavaScript engine. Therefore, after any change to the extension code, these steps have to be repeated to load the changes.

Next Steps

Now that your extension is enabled and you have a basic development environment, you can make changes to the source code and repeat the process to test them.

Next, you can prepare your extension for Translation into other languages, making it available to more users and potential contributors.

MIT Licensed | GJS, A GNOME Project