GitHub Actions Tutorial — JavaScript Actions
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 →