Script Studio: Writing Scripts

    This page describes how a script is written: its structure, the information it receives when it runs, how it communicates with Jira, how scripts share code, and how to run one.

    Note: 📹 Video placeholder — writing a script (6 minutes): using completion for the Jira API, running the script, reading the output, and moving shared code into a library file.

    1. The structure of a script

    A script is a TypeScript file containing a default exported function. That function is the entry point, whatever causes the script to run.

    import { jira } from 'jira-api';
    
    export default async function run(_getIssue: GetIssue, context: ScriptContext) {
      const me = await jira.get('/rest/api/3/myself');
      console.log('Running as', me.displayName);
      return me.accountId;
    }
    
    ElementPurpose
    The value returnedRecorded in the run history, returned to a caller of a REST endpoint, and stored as the value of a calculated field.
    console.log, console.warn, console.errorCaptured, timestamped and retained with the execution record.
    The first parameterRetained for compatibility with earlier releases. New scripts should use the Jira client described below and may name this parameter _getIssue.

    2. The execution context

    The second parameter indicates why the script is running and provides the objects relevant to that situation.

    PropertyPopulated whenContents
    triggerAlwaysHow the script was started: manual, schedule, event, field, rest, workflow or uimod
    actorAccountIdA manual runThe administrator who ran the script
    eventAn event triggerThe Jira event that started the script
    fieldA calculated fieldThe field being calculated and the issue it concerns
    requestA REST endpoint callThe incoming HTTP call
    workflowA workflow ruleThe transition, the issue, and, for a post function, the comment and change record
    uimodA UI modificationThe screen, project, issue type and issue the script is running against
    inputA manual run of a script that declares an input formThe values entered in that form
    variablesAlways, but see note belowThe installation's stored secrets, by name

    A single script may support several execution points by examining context.trigger. See Workflows, UI Modifications and Run Inputs and Script Variables for the detail of each, including the additional step a script must take before an automated trigger — anything other than a manual run — is allowed to see a given variable. Advanced: the contents of the remaining objects

    event contains key (the catalogue identifier, for example issue.created), type (the Jira event name, for example avi:jira:created:issue), subject (a short description of what changed, such as an issue key) and payload (the complete Jira event data).

    field contains id (the Jira custom field identifier), name, type, collection, issue (the issue being calculated), and the methods set(issue, value) and setMany(entries) for writing values to other issues.

    request contains source, method, path, headers, query, body, input (the payload, unwrapped) and the method respond(status, body, headers). Authorisation headers and cookies are not included.

    3. Communicating with Jira

    Scripts call the Jira REST API through a supplied client. Endpoint addresses are written as templates and the values are supplied separately.

    import { jira } from 'jira-api';
    
    // Reading an issue
    const issue = await jira.get('/rest/api/3/issue/{issueIdOrKey}', {
      path: { issueIdOrKey: 'PROJ-1' },
      query: { fields: ['summary', 'status', 'assignee'] }
    });
    
    // Adding a comment
    await jira.post('/rest/api/3/issue/{issueIdOrKey}/comment', {
      path: { issueIdOrKey: 'PROJ-1' },
      body: { body: { type: 'doc', version: 1, content: [] } }
    });
    

    The editor offers completion for every available endpoint, together with its parameters and the structure of its response.

    Note: A UI modification script is the one exception: it runs in the browser rather than on the server, has no access to this client, and calls Jira instead through uim.requestJira, as the person filling in the form. See UI Modifications. Advanced: endpoints outside the standard client

    The supplied client covers the Jira platform REST API. For endpoints outside it, such as the Agile API or Jira Service Management, scripts may use the Forge API client directly:

    import api, { route } from '@forge/api';
    
    const response = await api.asUser().requestJira(route`/rest/agile/1.0/board`);
    const { values } = await response.json();
    

    Arbitrary outbound network requests and web trigger creation are not available to scripts.

    4. Keeping data between executions

    A script that needs to remember something from one run to the next — a counter, a cache, a record of what has already been handled — can create its own SQL tables and read and write them directly. See Script Storage (SQL).

    5. Sharing code between scripts

    Scripts reference one another by relative path, in the same way as any TypeScript project. This is the mechanism for shared libraries; no additional configuration is required.

    // lib/jira-helpers.ts
    import { jira } from 'jira-api';
    
    /** Builds the document structure Jira requires for a comment or description. */
    export const paragraph = (text: string) => ({
      type: 'doc',
      version: 1,
      content: [{ type: 'paragraph', content: [{ type: 'text', text }] }]
    });
    
    /** The number of whole days between two dates. */
    export const daysBetween = (from: string | Date, to: string | Date = new Date()) =>
      Math.floor((new Date(to).getTime() - new Date(from).getTime()) / 86400000);
    
    /** Finds the identifier of a custom field by its name. */
    let fieldCache: Map<string, string> | null = null;
    export const fieldIdByName = async (name: string) => {
      if (!fieldCache) {
        const fields = await jira.get('/rest/api/3/field');
        fieldCache = new Map(fields
          .filter((f) => f.custom)
          .map((f) => [String(f.name || '').trim().toLowerCase(), String(f.id)]));
      }
      return fieldCache.get(name.trim().toLowerCase()) || '';
    };
    
    // schedules/nudge-quiet-items.ts
    import { jira } from 'jira-api';
    import { paragraph, daysBetween, fieldIdByName } from '../lib/jira-helpers';
    
    export default async function run() {
      const points = await fieldIdByName('Story Points');
      // …
    }
    

    Only files within the workspace may be referenced. External packages cannot be installed. Advanced: how references are resolved

    • The file extension is optional. ./lib/text matches lib/text.ts, then lib/text.js, then lib/text/index.ts. A reference written as ./lib/text.js also matches the corresponding .ts file.
    • References that would lead outside the workspace are rejected.
    • Two files that reference each other in a loop are rejected when the script is run, and the message names the files involved.
    • The file being run may contain unsaved changes; referenced files are read as saved. All open files are therefore saved automatically before a script is run.

    6. Running a script

    Press F5, or use the Run File command. If the script declares an input form, it is shown first; see Run Inputs and Script Variables. Output appears in the Script Studio output panel as the script runs, and the execution is added to the run history.

    Note: Breakpoints are not available. Scripts run on the Jira platform rather than in the browser, so diagnosis is carried out through the output panel and the run history.image-20260830-213352.png

    7. The Example Library

    Script Studio includes 80 complete, documented examples across 11 categories.

    CategoryExamples
    BasicsCurrent user, listing fields, JQL searches, reading an issue
    Work itemsCreating, cloning, transitioning by JQL, updating custom fields, linking, assigning
    CommentsAdding, listing, removing old comments, mentioning a group
    Hierarchy and rollupsTotalling sub-task estimates, epic story points, copying labels to linked items
    Event triggeredAutomatic assignment, creating sub-tasks, closing sub-tasks with the parent
    ScheduledEscalating stale work, marking items overdue, periodic reports
    Calculated fieldsDays in status, derived labels, readiness indicators, estimate rollups
    REST endpointsCreating an issue from an incoming webhook, reporting endpoints
    ConfigurationCustom field contexts and options, project roles, components, versions
    AgileBoards and sprints, sprint dates, sprint estimates by person
    PatternsPagination, reading the change history, date calculations, shared libraries

    The library is available in three forms:

    1. The browser, opened from the Properties panel toolbar. Examples can be filtered by category and by execution point, and searched by title, description or content. The full source is displayed alongside, and can be inserted at the cursor, copied, or saved as a new file.
    2. The Insert Example command, for inserting a known example directly.
    3. Completion suggestions, which offer the examples while a script is being written. image-20260830-213247.png

    8. Limits

    LimitValue
    Size of a single script32 KB
    Total size of a script and the files it references256 KB
    Number of files referenced by one script25
    Jira API calls in a single execution50
    Console output retained80 lines
    Returned value retained4 KB

    Execution time limits depend on how the script is started; see Security and Governance. SQL storage has its own limits; see Script Storage (SQL).

    Related pages