GitHub Actions Tutorial — JavaScript Actions

1 minute read

JavaScript Actions

JavaScript actions run directly on the runner (no container overhead) and use the official @actions/core and @actions/github packages to interact with the Actions runtime and GitHub API.


When to Use JavaScript Actions

Use Case Example
API interactions Comment on PRs, create issues, post reviews
Complex logic Parsing, validation, conditional branching
Performance-sensitive Starts instantly (no Docker pull)
Cross-platform Works on Linux, Windows, macOS runners

Project Structure

my-js-action/
├── action.yml          # metadata
├── index.js            # entry point
├── package.json
├── package-lock.json
├── node_modules/       # committed or bundled
└── dist/               # bundled output (if using ncc)
    └── index.js

Basic JavaScript Action

action.yml:


name: 'Hello World Action'
description: 'Greets someone'

inputs:
  who-to-greet:
    description: 'Who to greet'
    required: true

outputs:
  time:
    description: 'Greeting time'

runs:
  using: 'node20'
  main: 'dist/index.js'

index.js:

const core = require('@actions/core');

try {
  const name = core.getInput('who-to-greet');
  console.log(`Hello, ${name}!`);

  const time = new Date().toISOString();
  core.setOutput('time', time);
} catch (error) {
  core.setFailed(error.message);
}

Actions Toolkit Packages

Package Purpose
@actions/core Inputs, outputs, logging, secrets, failures
@actions/github Authenticated Octokit client
@actions/exec Run shell commands
@actions/io File system operations
@actions/cache Cache management
@actions/artifact Artifact upload/download
@actions/tool-cache Download and cache tools

Install

npm init -y
npm install @actions/core @actions/github

GitHub API Example

Post a comment on a pull request:

const core = require('@actions/core');
const github = require('@actions/github');

async function run() {
  try {
    const token = core.getInput('github-token');
    const message = core.getInput('message');

    const octokit = github.getOctokit(token);
    const context = github.context;

    if (context.payload.pull_request) {
      await octokit.rest.issues.createComment({
        owner: context.repo.owner,
        repo: context.repo.repo,
        issue_number: context.payload.pull_request.number,
        body: message,
      });
      core.info('Comment posted successfully');
    } else {
      core.warning('Not a pull request event');
    }
  } catch (error) {
    core.setFailed(error.message);
  }
}

run();

Bundling with ncc

Commit node_modules or bundle with @vercel/ncc:

npm install -D @vercel/ncc
npx ncc build index.js -o dist

Then point action.yml to the bundled file:

runs:
  using: 'node20'
  main: 'dist/index.js'

Bundling produces a single file with all dependencies — no need to commit node_modules.


Common Mistakes

Mistake Fix
node_modules not found Bundle with ncc or commit node_modules
Using wrong Node version Set using: 'node20' in action.yml
Secrets logged to console Use core.setSecret(value) to mask them
Unhandled promise rejection Wrap async code in try/catch and call core.setFailed()

Quick Reference

Concept Detail
Runtime using: 'node20'
Entry point main: 'dist/index.js'
Get input core.getInput('name')
Set output core.setOutput('key', 'value')
Fail core.setFailed('message')
GitHub client github.getOctokit(token)
Bundle npx ncc build index.js -o dist

← Previous: Composite Actions

Next: Docker Actions →

Updated: