Mastodon Glitch Edition

Flavours and Skins

Upstream Mastodon supports changing the site CSS on a per-user basis by specifying files in a special config/themes.yml file. This approach works for simple themes, but it has its limitations:

  1. You can only change the CSS of a page, not its JavaScript or other elements.
  2. The same theme is applied to all pages, regardless of type.

glitch-soc uses a flavour+skin system which addresses both of these problems, while making the creation of themes even simpler than it is on upstream. The system works as follows:

  1. Each instance can have any number of flavours, which can contain JavaScript, CSS, or anything else. By default, glitch-soc comes with two flavours: glitch, which is the default, and vanilla, which is the frontend used by upstream.

  2. Each flavour can have any number of skins, which are alternate stylesheets used with the flavour. The win95 theme from cybrespace:mastodon is an example alternate skin for the vanilla flavour.

The flavour and skin of the Mastodon web app can be changed in the user preferences. For details on creating and installing additional skins and flavours, see below.


To install an existing flavour or skin, you need only to place the flavour or skin file/folder into the appropriate location. For flavours, this is:


For skins (where FLAVOUR-NAME is the name of the flavour that the skin applies to), this is:


Mastodon will automatically detect flavours and skins installed into these locations, although you will likely have to restart your server (and, naturally, recompile your assets). This system works well with installation methods such as git submodules, although of course you can simply add the files manually as well.


Glitch skins are automatically loaded from the folder app/javascript/skins/FLAVOUR-NAME/, where FLAVOUR-NAME is the name of the flavour that the skin should apply to. For example, if you are looking to reskin the glitch flavour, you should place your skin in the file app/javascript/skins/glitch/.

The simplest skin is just a single (S)CSS file, the name of which will be taken as the name of the skin. This stylesheet will be served instead of the common styles, which hold all of Mastodon’s default styling. When you specify a skin, the default styling for a flavour is not automatically loaded, so be sure to import it in your stylesheet if needed.


If you want to provide different stylesheets for various pages, you can do this by providing a folder instead of a single stylesheet as your skin. This folder should contain a number of files, each of which provides the styling for a different pack, which is served depending on page type. The available packs are as follows:

The names of the files inside the skin folder should match the pack that they are meant to replace. For example, if I have styling that I want to show on the web app but not on static pages, I should specify it in app/javascript/skins/FLAVOUR-NAME/SKIN-NAME/home.scss.

The glitch and vanilla flavours only use the common pack for styling, but you are welcome to add additional styles to other packs if you wish.


Like skins, flavours are all loaded from a specific folder; namely, app/javascript/flavours. Flavours are specified as folders with a special file, called theme.yml, which provides the necessarily metadata for Mastodon to load its files. Aside from this one required file, the contents of a flavour folder are left entirely up to authors.

The theme.yml for a flavour must have a pack property, whose own properties specify the JavaScript files to load for each pack (see above). These properties must have one of the following values:

Here is a sample theme.yml file that could be used to generate a flavour:

pack:  #  Pack files
  common:  #  Options for the `common` pack
    filename: pack/common.js  #  This file contains all the scripts and styles for the pack
    stylesheet: true  #  This must be specified for packs which serve styling
  home: pack/home.js  #  A string can be used if only a filename is needed

fallback: glitch  #  The fallback flavour for any unspecified packs

Pack options

The following options can be provided to packs:


The locales property specifies a folder from which to draw locale files to be served with your JavaScript. The contents of this directory must be .js or .json files whose names correspond to language tags and whose default exports are a messages object of the same form as provided by vanilla Mastodon. This messages object can be made accessible in your source by importing getLocale() from locales.


You can specify one or more screenshots to render in the flavour’s description page using the screenshot property. Webpack ignores the paths of image assets, so this property should specify only the filename. It is a good idea to namespace the filename of this file using your flavour name to guarantee uniqueness.

The value of the screenshot property must be an image file that Webpack already knows about—we won’t try to load it for you. Requiring it somewhere in one of your JavaScript files is probably sufficient.


The fallback property specifies a flavour or flavours from which to draw unspecified packs. By default, unspecified packs are drawn from the default theme. The value of this property can be either the name of a flavour, or an array of names, in which case the first present flavour will be used. Setting this property to null disables fallback behaviour.

Pack directory

Generally speaking, your pack files should be inside of your flavour folder. If for some reason they aren’t (as is the case with the vanilla flavour, to maintain upstream compatibility), you can specify a different folder inside which to look for packs with the pack_directory property. This should have a string value, and is resolved relative to the application root, not app/javascript.


You can provide localization strings for your skins and/or flavours by including a names.yml file inside the skin/flavour folder. For themes, this file should take the following form:

      description: [A description of your flavour]
      name: [Your flavour's name]
      default: [The name of the default skin for your flavour]
# …more localizations for other languages

For skins, you only need the skins part of the above file:

      SKIN-NAME: [The name of your skin]
# …more localizations for other languages

This file is loaded alongside all of the other localization data when your server first starts.