GitHub Actions CI/CD for NetSuite
Automate your NetSuite SDF deployments using GitHub Actions. This guide covers complete workflow templates, use cases, and step-by-step setup instructions.
Why Use GitHub Actions for NetSuite?
When to Use GitHub Actions
| Use Case | Recommended? | Reason |
|---|---|---|
| Team of 2+ developers | ✅ Yes | Ensures consistent deployments |
| Multiple environments | ✅ Yes | Automates promotion path |
| Frequent releases | ✅ Yes | Reduces manual effort |
| Compliance requirements | ✅ Yes | Provides audit trail |
| Solo developer, infrequent changes | ⚠️ Optional | Manual may be sufficient |
CI/CD Flow Overview
Prerequisites
Before setting up GitHub Actions, ensure you have:
1. NetSuite Account Configuration
# Required token-based authentication credentials
NETSUITE_ACCOUNT_ID # Your NetSuite account ID (e.g., TSTDRV1234567)
NETSUITE_TOKEN_ID # Token ID from NetSuite
NETSUITE_TOKEN_SECRET # Token Secret from NetSuite
2. Generate Token-Based Authentication (TBA) Credentials
3. Add GitHub Repository Secrets
Navigate to your repository: Settings → Secrets and variables → Actions
| Secret Name | Description | Example |
|---|---|---|
NS_ACCOUNT_ID_SANDBOX | Sandbox account ID | TSTDRV1234567 |
NS_TOKEN_ID_SANDBOX | Sandbox token ID | abc123... |
NS_TOKEN_SECRET_SANDBOX | Sandbox token secret | xyz789... |
NS_ACCOUNT_ID_PROD | Production account ID | 1234567 |
NS_TOKEN_ID_PROD | Production token ID | def456... |
NS_TOKEN_SECRET_PROD | Production token secret | uvw321... |
Workflow Templates
Template 1: Validation on Pull Request
Validates SDF project on every pull request to catch issues early.
# .github/workflows/validate-sdf.yml
name: Validate SDF Project
on:
pull_request:
branches: [main, develop]
paths:
- 'src/**'
- 'Objects/**'
- 'FileCabinet/**'
- 'manifest.xml'
jobs:
validate:
name: Validate SDF Project
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install SuiteCloud CLI
run: npm install -g @oracle/suitecloud-cli
- name: Validate project structure
run: |
echo "📋 Checking project structure..."
if [ ! -f "manifest.xml" ]; then
echo "❌ manifest.xml not found"
exit 1
fi
if [ ! -d "Objects" ]; then
echo "❌ Objects directory not found"
exit 1
fi
echo "✅ Project structure valid"
- name: Validate SDF project
run: |
echo "🔍 Running SDF validation..."
suitecloud project:validate
echo "✅ SDF validation passed"
- name: Comment on PR
if: success()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ **SDF Validation Passed**\n\nProject structure and objects validated successfully.'
})
Template 2: Deploy to Sandbox on Merge
Automatically deploys to sandbox when code is merged to develop branch.
# .github/workflows/deploy-sandbox.yml
name: Deploy to Sandbox
on:
push:
branches: [develop]
paths:
- 'src/**'
- 'Objects/**'
- 'FileCabinet/**'
env:
NODE_VERSION: '18'
jobs:
deploy-sandbox:
name: Deploy to Dev Sandbox
runs-on: ubuntu-latest
environment: sandbox
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install SuiteCloud CLI
run: npm install -g @oracle/suitecloud-cli
- name: Configure SuiteCloud account
run: |
suitecloud account:savetoken \
--account ${{ secrets.NS_ACCOUNT_ID_SANDBOX }} \
--authid "GitHubActions" \
--tokenid ${{ secrets.NS_TOKEN_ID_SANDBOX }} \
--tokensecret ${{ secrets.NS_TOKEN_SECRET_SANDBOX }}
- name: Validate before deploy
run: suitecloud project:validate
- name: Deploy to Sandbox
run: |
echo "🚀 Deploying to Sandbox..."
suitecloud project:deploy --accountspecificvalues WARNING
echo "✅ Deployment complete"
- name: Deployment Summary
run: |
echo "## 🎉 Sandbox Deployment Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Environment | Sandbox |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | ${{ github.ref_name }} |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | ${{ github.sha }} |" >> $GITHUB_STEP_SUMMARY
echo "| Deployed by | ${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
Template 3: Production Deployment with Approval
Deploys to production with manual approval gate and backup.
# .github/workflows/deploy-production.yml
name: Deploy to Production
on:
push:
branches: [main]
paths:
- 'src/**'
- 'Objects/**'
- 'FileCabinet/**'
workflow_dispatch:
inputs:
deploy_type:
description: 'Deployment type'
required: true
default: 'full'
type: choice
options:
- full
- partial
env:
NODE_VERSION: '18'
jobs:
# Job 1: Validate
validate:
name: Validate Project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install and Validate
run: |
npm install -g @oracle/suitecloud-cli
suitecloud project:validate
# Job 2: Approval Gate
approval:
name: Await Approval
needs: validate
runs-on: ubuntu-latest
environment: production
steps:
- name: Approval checkpoint
run: echo "✅ Deployment approved by ${{ github.actor }}"
# Job 3: Backup
backup:
name: Backup Production
needs: approval
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install SuiteCloud CLI
run: npm install -g @oracle/suitecloud-cli
- name: Configure Production Account
run: |
suitecloud account:savetoken \
--account ${{ secrets.NS_ACCOUNT_ID_PROD }} \
--authid "GitHubActions" \
--tokenid ${{ secrets.NS_TOKEN_ID_PROD }} \
--tokensecret ${{ secrets.NS_TOKEN_SECRET_PROD }}
- name: Backup current production objects
run: |
echo "📦 Creating backup..."
mkdir -p backup
suitecloud object:import --destinationfolder backup --scriptid "customscript_*" || true
echo "✅ Backup created"
- name: Upload backup artifact
uses: actions/upload-artifact@v4
with:
name: production-backup-${{ github.run_number }}
path: backup/
retention-days: 30
# Job 4: Deploy
deploy:
name: Deploy to Production
needs: backup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install SuiteCloud CLI
run: npm install -g @oracle/suitecloud-cli
- name: Configure Production Account
run: |
suitecloud account:savetoken \
--account ${{ secrets.NS_ACCOUNT_ID_PROD }} \
--authid "GitHubActions" \
--tokenid ${{ secrets.NS_TOKEN_ID_PROD }} \
--tokensecret ${{ secrets.NS_TOKEN_SECRET_PROD }}
- name: Deploy to Production
run: |
echo "🚀 Deploying to Production..."
suitecloud project:deploy --accountspecificvalues WARNING
echo "✅ Production deployment complete"
- name: Create Git tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "release-${{ github.run_number }}" -m "Production release #${{ github.run_number }}"
git push origin "release-${{ github.run_number }}"
- name: Production Summary
run: |
echo "## 🎉 Production Deployment Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Environment | Production |" >> $GITHUB_STEP_SUMMARY
echo "| Release Tag | release-${{ github.run_number }} |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | ${{ github.sha }} |" >> $GITHUB_STEP_SUMMARY
echo "| Approved by | ${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
echo "| Backup | production-backup-${{ github.run_number }} |" >> $GITHUB_STEP_SUMMARY
Template 4: Multi-Environment Pipeline
Complete pipeline for Dev → QA → UAT → Production flow.
# .github/workflows/multi-env-pipeline.yml
name: Multi-Environment Pipeline
on:
push:
branches:
- develop
- 'release/*'
- main
workflow_dispatch:
inputs:
target_env:
description: 'Target environment'
required: true
type: choice
options:
- dev
- qa
- uat
- production
env:
NODE_VERSION: '18'
jobs:
# Determine target environment
setup:
name: Determine Environment
runs-on: ubuntu-latest
outputs:
environment: ${{ steps.set-env.outputs.environment }}
account_id_secret: ${{ steps.set-env.outputs.account_id_secret }}
token_id_secret: ${{ steps.set-env.outputs.token_id_secret }}
token_secret_secret: ${{ steps.set-env.outputs.token_secret_secret }}
steps:
- name: Set environment based on branch
id: set-env
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
ENV="${{ github.event.inputs.target_env }}"
elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
ENV="dev"
elif [[ "${{ github.ref }}" == refs/heads/release/* ]]; then
ENV="qa"
elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
ENV="production"
else
ENV="dev"
fi
echo "environment=$ENV" >> $GITHUB_OUTPUT
case $ENV in
dev)
echo "account_id_secret=NS_ACCOUNT_ID_DEV" >> $GITHUB_OUTPUT
echo "token_id_secret=NS_TOKEN_ID_DEV" >> $GITHUB_OUTPUT
echo "token_secret_secret=NS_TOKEN_SECRET_DEV" >> $GITHUB_OUTPUT
;;
qa)
echo "account_id_secret=NS_ACCOUNT_ID_QA" >> $GITHUB_OUTPUT
echo "token_id_secret=NS_TOKEN_ID_QA" >> $GITHUB_OUTPUT
echo "token_secret_secret=NS_TOKEN_SECRET_QA" >> $GITHUB_OUTPUT
;;
uat)
echo "account_id_secret=NS_ACCOUNT_ID_UAT" >> $GITHUB_OUTPUT
echo "token_id_secret=NS_TOKEN_ID_UAT" >> $GITHUB_OUTPUT
echo "token_secret_secret=NS_TOKEN_SECRET_UAT" >> $GITHUB_OUTPUT
;;
production)
echo "account_id_secret=NS_ACCOUNT_ID_PROD" >> $GITHUB_OUTPUT
echo "token_id_secret=NS_TOKEN_ID_PROD" >> $GITHUB_OUTPUT
echo "token_secret_secret=NS_TOKEN_SECRET_PROD" >> $GITHUB_OUTPUT
;;
esac
validate:
name: Validate
needs: setup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Validate
run: |
npm install -g @oracle/suitecloud-cli
suitecloud project:validate
deploy:
name: Deploy to ${{ needs.setup.outputs.environment }}
needs: [setup, validate]
runs-on: ubuntu-latest
environment: ${{ needs.setup.outputs.environment }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install SuiteCloud CLI
run: npm install -g @oracle/suitecloud-cli
- name: Configure account
env:
ACCOUNT_ID: ${{ secrets[needs.setup.outputs.account_id_secret] }}
TOKEN_ID: ${{ secrets[needs.setup.outputs.token_id_secret] }}
TOKEN_SECRET: ${{ secrets[needs.setup.outputs.token_secret_secret] }}
run: |
suitecloud account:savetoken \
--account "$ACCOUNT_ID" \
--authid "GitHubActions" \
--tokenid "$TOKEN_ID" \
--tokensecret "$TOKEN_SECRET"
- name: Deploy
run: |
echo "🚀 Deploying to ${{ needs.setup.outputs.environment }}..."
suitecloud project:deploy --accountspecificvalues WARNING
echo "✅ Deployment complete"
- name: Summary
run: |
echo "## Deployment to ${{ needs.setup.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "✅ Successfully deployed" >> $GITHUB_STEP_SUMMARY
Template 5: Partial/Selective Deployment
Deploy specific scripts or objects only.
# .github/workflows/deploy-partial.yml
name: Partial Deployment
on:
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- sandbox
- production
script_ids:
description: 'Script IDs to deploy (comma-separated)'
required: true
type: string
default: 'customscript_example'
jobs:
deploy-partial:
name: Partial Deploy to ${{ github.event.inputs.environment }}
runs-on: ubuntu-latest
environment: ${{ github.event.inputs.environment }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install SuiteCloud CLI
run: npm install -g @oracle/suitecloud-cli
- name: Configure account
run: |
if [ "${{ github.event.inputs.environment }}" == "production" ]; then
suitecloud account:savetoken \
--account ${{ secrets.NS_ACCOUNT_ID_PROD }} \
--authid "GitHubActions" \
--tokenid ${{ secrets.NS_TOKEN_ID_PROD }} \
--tokensecret ${{ secrets.NS_TOKEN_SECRET_PROD }}
else
suitecloud account:savetoken \
--account ${{ secrets.NS_ACCOUNT_ID_SANDBOX }} \
--authid "GitHubActions" \
--tokenid ${{ secrets.NS_TOKEN_ID_SANDBOX }} \
--tokensecret ${{ secrets.NS_TOKEN_SECRET_SANDBOX }}
fi
- name: Deploy specific objects
run: |
echo "🚀 Deploying: ${{ github.event.inputs.script_ids }}"
suitecloud object:deploy \
--scriptid "${{ github.event.inputs.script_ids }}" \
--accountspecificvalues WARNING
echo "✅ Partial deployment complete"
- name: Summary
run: |
echo "## Partial Deployment" >> $GITHUB_STEP_SUMMARY
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Environment | ${{ github.event.inputs.environment }} |" >> $GITHUB_STEP_SUMMARY
echo "| Objects | ${{ github.event.inputs.script_ids }} |" >> $GITHUB_STEP_SUMMARY
Which Template Should I Use?
| Scenario | Recommended Template | Key Features |
|---|---|---|
| Solo developer, simple project | Template 1 + Manual | PR validation only |
| Small team, single sandbox | Template 1 + 2 | Auto sandbox deploy |
| Medium team, approval needed | Template 1 + 2 + 3 | Full pipeline with approval |
| Enterprise, multi-environment | Template 4 | Complete Dev→QA→UAT→Prod |
| Hotfix deployment | Template 5 | Selective object deploy |
| Compliance requirements | Template 3 + 4 | Approval gates + backup |
See the Deployment Decision Guide for detailed scenarios comparing CI/CD Pipeline vs Single File Upload vs Manual Deploy.
Step-by-Step Setup Guide
Step 1: Repository Structure
Ensure your repository follows this structure:
your-sdf-project/
├── .github/
│ └── workflows/
│ ├── validate-sdf.yml
│ ├── deploy-sandbox.yml
│ └── deploy-production.yml
├── FileCabinet/
│ └── SuiteScripts/
│ └── your_scripts.js
├── Objects/
│ └── customscript_*.xml
├── src/
│ └── (TypeScript source if using)
├── manifest.xml
└── project.json
Step 2: Create Workflow Files
Step 3: Configure GitHub Environments
For production protection, create environments:
- Go to Settings → Environments
- Create
sandboxenvironment (no protection needed) - Create
productionenvironment with:- ✅ Required reviewers (add team leads)
- ✅ Wait timer (optional, e.g., 5 minutes)
- ✅ Limit to specific branches:
main
Complete Pipeline Flow Diagram
Related Documentation
- Deployment Decision Guide - When to use CI/CD vs Single File Upload
- Deployment Workflow Guide - Manual deployment methods
- Deploy to Sandbox - Detailed sandbox deployment
- Deploy to Production - Production deployment details
- Rollback - Handling deployment issues
- Git Workflows - Git branching strategies