Skip to main content
Redmine’s plugin system lets you extend the application without modifying core files. Plugins can add controllers, models, views, routes, menu items, permissions, migrations, and hooks — all from a self-contained directory under plugins/.

How plugins are loaded

Redmine uses Redmine::PluginLoader to discover and load plugins. At startup it:
  1. Scans every subdirectory of plugins/ and creates a PluginPath object for each one.
  2. Adds each plugin’s lib/ directory to Rails’ autoload paths.
  3. After all eager-loading is done, runs each plugin’s init.rb initializer.
  4. Fires the :after_plugins_loaded hook so plugins can react to the fully-loaded state.
# lib/redmine/plugin_loader.rb (simplified)
module Redmine
  class PluginLoader
    def self.load
      setup
      add_autoload_paths

      Rails.application.config.to_prepare do
        PluginLoader.directories.each(&:run_initializer)
        Redmine::Hook.call_hook :after_plugins_loaded
      end
    end
  end
end
The init.rb file is the entry point for every plugin. It calls Redmine::Plugin.register to declare the plugin’s metadata and configure its integration points.

Plugin directory structure

A standard plugin follows the same Rails conventions as the Redmine core, placed inside plugins/<plugin_name>/.
plugins/
└── my_plugin/
    ├── init.rb                        # Required — plugin entry point
    ├── README.rdoc
    ├── app/
    │   ├── controllers/
    │   ├── helpers/
    │   ├── models/
    │   └── views/
    ├── assets/
    │   ├── images/
    │   ├── javascripts/
    │   └── stylesheets/
    ├── config/
    │   ├── locales/
    │   │   └── en.yml
    │   └── routes.rb
    ├── db/
    │   └── migrate/
    ├── lib/
    │   └── tasks/
    └── test/
        ├── fixtures/
        ├── functional/
        ├── integration/
        ├── system/
        └── unit/
Only init.rb is required. You can omit any directory you do not need.

The init.rb entry point

Every plugin registers itself with Redmine::Plugin.register. The block is evaluated in the context of the plugin object, giving you access to all registration methods.
# plugins/my_plugin/init.rb
Redmine::Plugin.register :my_plugin do
  name 'My Plugin'
  author 'Jane Smith'
  description 'Adds extra functionality to Redmine'
  version '1.0.0'
  url 'https://example.com/my_plugin'
  author_url 'https://example.com/about'

  requires_redmine version_or_higher: '5.0.0'
end

Plugin registration API

The following methods are available inside the register block.
Metadata fields displayed on the Administration > Plugins page.
name 'My Plugin'
author 'Jane Smith'
version '1.2.3'
Raises Redmine::PluginRequirementError at load time if the running Redmine version does not satisfy the requirement.
# Redmine 5.0.0 or higher
requires_redmine version_or_higher: '5.0.0'

# Exactly 5.1.x
requires_redmine version: '5.1'

# One of several versions
requires_redmine version: ['5.0.0', '5.1.0']

# A range
requires_redmine version: '5.0.0'..'5.9.9'
Raises Redmine::PluginRequirementError if another plugin is not installed or its version is insufficient.
requires_redmine_plugin :some_other_plugin, version_or_higher: '1.0.0'
Registers access-control permissions, optionally grouped under a project module that users can enable per project.
project_module :my_plugin do
  permission :view_my_plugin, { my_plugin: [:index, :show] }, public: true
  permission :edit_my_plugin, { my_plugin: [:new, :create, :edit, :update] }
end
Declares configurable settings for the plugin. See Plugin settings for details.
settings default: { 'notify' => true, 'max_items' => 10 },
         partial: 'settings/my_plugin_settings'
Registers a model as a source of events in the Activity feed.
activity_provider :my_events, class_name: 'MyEvent'
Registers a custom wiki formatter.
wiki_format_provider(:my_formatter, MyFormatter, label: 'My Formatter')

Plugin lifecycle

Rails boot
  └─ PluginLoader.load
        ├─ scan plugins/ directory
        ├─ add plugin lib/ paths to autoloader
        └─ to_prepare callback (runs before each request in development)
              ├─ run each plugin's init.rb
              │     └─ Redmine::Plugin.register :my_plugin do ... end
              │           ├─ load i18n files from config/locales/
              │           ├─ prepend app/views/ to view paths
              │           └─ define plugin settings if declared
              └─ call_hook :after_plugins_loaded

Generating a plugin scaffold

Redmine ships with a generator that creates the full directory structure and starter files:
bundle exec rails generate redmine_plugin my_plugin
Additional generators are available for controllers, models, and migrations:
bundle exec rails generate redmine_plugin_controller my_plugin things index show
bundle exec rails generate redmine_plugin_model my_plugin thing name:string
bundle exec rails generate redmine_plugin_migration my_plugin create_things

Build your first plugin

Follow the step-by-step tutorial to create a working plugin from scratch.