Backend Development 14 min read

How Jira’s Forge Plugin System Enables Fast, Secure, Server‑Driven Extensions

This article explores Jira's plugin ecosystem, detailing how the Forge platform lets developers create, integrate, and deploy extensions using CLI tools, UI kit or custom UI, with server‑driven rendering, sandboxed security, and a marketplace for distribution.

KooFE Frontend Team
KooFE Frontend Team
KooFE Frontend Team
How Jira’s Forge Plugin System Enables Fast, Secure, Server‑Driven Extensions
This article is a research and summary of Jira’s plugin system.

Plugins are a common component of software systems, allowing flexible, customizable, and extensible modules that can be added without modifying the core code. In SaaS, plugins provide functionality extension, customization, and integration, enhancing flexibility and fostering ecosystem growth.

Function extension: add new features to meet specific business needs.

Customization: tailor the application to user preferences and workflows.

Collaboration and integration: enable seamless data sharing across services.

Designing a plugin system must consider developers, users, and the host system, providing capabilities for development, integration, and a marketplace.

Plugin development: tools, templates, API docs, SDKs.

Plugin integration: simple yet powerful APIs for embedding.

Plugin marketplace: a store for publishing and distributing plugins.

Jira, an Atlassian project‑tracking tool, supports plugins via the Forge platform. Development begins with installing the CLI, logging in, and creating a project from a template.

CLI

Using Forge CLI, a simple "Hello World" plugin is built with the following steps: login, create, deploy, and install.

login – authenticate with an Atlassian API token create – generate a plugin project from a template deploy – build, compile, and deploy the code install – install the app on a site with required API permissions

Forge uses JSX syntax; an IssuePanel plugin with a counter is implemented as:

<code>import ForgeUI, { render, Fragment, Text, IssuePanel, Button, useState } from "@forge/ui";

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <Fragment>
      <Text>{count}</Text>
      <Button onClick={() => { setCount(count + 1); }} text="click" />
    </Fragment>
  );
};

export const run = render(
  <IssuePanel>
    <App />
  </IssuePanel>
);
</code>

The

manifest.yml

defines the plugin configuration:

<code>modules:
  jira:issuePanel:
    - key: hello-world-app-hello-world-panel
      function: main
      title: hello-world-app
      icon: https://developer.atlassian.com/platform/forge/images/icons/issue-panel-icon.svg
function:
  - key: main
    handler: index.run
app:
  id: ari:cloud:ecosystem::app/xxxxxx-xxxx-xxxx-xxx-xxxxxx
</code>

After deployment, the plugin appears in Jira's Issue panel.

Unified Design

Forge offers two UI options:

UI kit – for simple scenarios, provides Atlassian‑styled components rendered server‑side.

Custom UI – for complex cases, uses static assets (HTML, CSS, JS) served in an iframe, giving developers full flexibility.

Plugin Rendering

Jira supports two rendering modes:

Inline Rendering

Plugins return JSON describing the UI hierarchy, which the host renders. Example JSON for the counter plugin is shown below.

<code>{
  "type": "render",
  "aux": {
    "type": "View",
    "children": [
      {
        "children": [
          {
            "type": "Text",
            "props": { "text": "0" }
          },
          {
            "type": "Button",
            "props": { "text": "click", "onClick": { "componentKey": "Button.0.0", "prop": "onClick" } }
          }
        ],
        "type": "IssuePanel"
      }
    ]
  }
}
</code>

This approach loads minimal static resources, offers better security (logic runs in a FaaS), and simplifies multi‑device adaptation.

Embedded Rendering

For complex UI, a custom UI is embedded via an iframe, which may have UX challenges like overlay issues but provides ample space for rich interfaces.

Data Communication

UI kit plugins can access context data with

useProductContext

:

<code>import ForgeUI, { useProductContext, Text, Macro, render } from '@forge/ui';

const App = () => {
  const context = useProductContext();
  return <Text>All info about my context: {JSON.stringify(context)}</Text>;
};

export const run = render(<Macro app={<App />} />);
</code>

Custom UI plugins retrieve context via

view.getContext()

:

<code>import { view } from '@forge/bridge';

const context = await view.getContext();
</code>

Plugins can listen to events, e.g., issue changes:

<code>import { events } from '@forge/bridge';

events.on('JIRA_ISSUE_CHANGED', data => {
  console.log('JIRA_ISSUE_CHANGED (Forge)', data);
});
</code>

Security

Forge ensures security through sandboxed execution, data isolation, and authentication. UI kit runs declaratively on the server, while custom UI assets are served in a sandboxed iframe with a strict Content‑Security‑Policy.

Plugin Types

Common plugin types include:

action – menu actions that trigger dialogs.

panel – UI rendered in a side panel.

page – standalone pages.

trigger – scheduled tasks, product events, or HTTP requests.

Additional types: custom field, background script, etc.

Plugin Marketplace

The marketplace provides installation, uninstallation, and configuration of plugins, serving as a distribution channel.

Conclusion

This article summarizes research on Jira’s plugin system, covering development, integration, rendering modes, security, and marketplace considerations, offering insights for building extensible Atlassian applications.

serverlessplugin developmentJiracustom UIForgeUI kit
KooFE Frontend Team
Written by

KooFE Frontend Team

Follow the latest frontend updates

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.