A Node.js command-line tool that automates versioning and changelog generation for projects following the Conventional Commits specification.
—
Standard Version provides comprehensive lifecycle hook support, allowing custom scripts to run at specific stages of the release process. This enables integration with build systems, testing frameworks, deployment pipelines, and custom validation workflows.
Core function for executing lifecycle hook scripts.
/**
* Execute lifecycle script for specified hook name
* @param {Object} args - Configuration object containing scripts definition
* @param {string} hookName - Name of the lifecycle hook to execute
* @returns {Promise<string>} Promise resolving to script output (stdout)
* @throws {Error} If script execution fails or returns non-zero exit code
*/
async function runLifecycleScript(args, hookName);Usage Examples:
const runLifecycleScript = require('standard-version/lib/run-lifecycle-script');
const config = {
scripts: {
prebump: 'npm run test',
postbump: 'npm run build',
posttag: 'npm publish'
},
silent: false
};
try {
// Execute prebump hook
const output = await runLifecycleScript(config, 'prebump');
console.log('Prebump output:', output);
// Execute hook that doesn't exist (returns resolved promise)
await runLifecycleScript(config, 'nonexistent'); // No-op
} catch (error) {
console.error('Script failed:', error.message);
}Standard Version supports hooks at eight key stages of the release process.
/**
* Lifecycle hook execution order and timing:
*
* 1. prerelease - Before any release processing begins
* 2. prebump - Before version calculation and file updates
* 3. postbump - After version bump, before changelog generation
* 4. prechangelog- Before changelog generation
* 5. postchangelog - After changelog generation, before commit
* 6. precommit - Before git commit creation
* 7. postcommit - After git commit, before tag creation
* 8. pretag - Before git tag creation
* 9. posttag - After git tag creation (final step)
*/Hook Execution Flow:
// Standard Version execution flow with hooks:
await runLifecycleScript(args, 'prerelease');
// → Validate environment, prepare workspace
await runLifecycleScript(args, 'prebump');
// → Run tests, lint code, validate dependencies
const newVersion = await bump(args, currentVersion);
await runLifecycleScript(args, 'postbump');
// → Build artifacts, update documentation
await runLifecycleScript(args, 'prechangelog');
// → Generate additional release notes, validate commits
await changelog(args, newVersion);
await runLifecycleScript(args, 'postchangelog');
// → Format changelog, add custom sections
await runLifecycleScript(args, 'precommit');
// → Final validation, security checks
await commit(args, newVersion);
await runLifecycleScript(args, 'postcommit');
// → Notify systems, prepare for tagging
await runLifecycleScript(args, 'pretag');
// → Final pre-tag validation
await tag(newVersion, isPrivate, args);
await runLifecycleScript(args, 'posttag');
// → Publish packages, deploy, notify stakeholdersConfigure lifecycle hooks through the scripts configuration object.
interface LifecycleScripts {
prerelease?: string; // Before any release processing
prebump?: string; // Before version calculation
postbump?: string; // After version bump
prechangelog?: string; // Before changelog generation
postchangelog?: string; // After changelog generation
precommit?: string; // Before git commit
postcommit?: string; // After git commit
pretag?: string; // Before git tag
posttag?: string; // After git tag (final)
}Usage Examples:
{
"scripts": {
"prerelease": "echo 'Starting release process'",
"prebump": "npm run lint && npm run test",
"postbump": "npm run build:prod",
"prechangelog": "node scripts/gather-contributors.js",
"postchangelog": "node scripts/format-changelog.js",
"precommit": "npm run security-audit",
"postcommit": "echo 'Changes committed successfully'",
"pretag": "npm run validate-build",
"posttag": "npm publish && npm run deploy"
}
}Typical use cases and patterns for each lifecycle hook.
Development and Testing Hooks:
{
"scripts": {
"prerelease": "git status --porcelain | grep -q . && exit 1 || echo 'Working directory clean'",
"prebump": "npm run lint && npm run test && npm run test:integration",
"postbump": "npm run build && npm run test:build"
}
}Build and Deployment Hooks:
{
"scripts": {
"postbump": "npm run build:prod && npm run compress-assets",
"postchangelog": "node scripts/update-docs.js",
"precommit": "npm run validate-bundle-size",
"posttag": "npm publish && docker build -t myapp:$npm_package_version ."
}
}Notification and Integration Hooks:
{
"scripts": {
"prerelease": "slack-notify 'Starting release for $npm_package_name'",
"postcommit": "git push origin main",
"posttag": "github-release create --tag $npm_package_version && slack-notify 'Released $npm_package_version'"
}
}Hooks have access to npm environment variables and can use them for dynamic behavior.
/**
* Available environment variables in hook scripts:
* - npm_package_name - Package name from package.json
* - npm_package_version - Current version from package.json
* - npm_config_* - npm configuration values
* - Standard shell environment variables
*/Usage Examples:
{
"scripts": {
"postbump": "echo 'Building $npm_package_name version $npm_package_version'",
"posttag": "docker tag myapp:latest myapp:$npm_package_version",
"precommit": "echo 'Committing version $npm_package_version' >> release.log"
}
}Advanced hook configurations for sophisticated workflows.
Multi-step Hook with Error Handling:
{
"scripts": {
"prebump": "npm run lint && npm run test && npm run security-check || (echo 'Pre-bump validation failed' && exit 1)",
"postbump": "npm run build && npm run package && npm run verify-package",
"posttag": "npm publish && npm run deploy-docs && npm run notify-slack"
}
}Conditional Hook Execution:
{
"scripts": {
"prebump": "[ \"$CI\" = \"true\" ] && npm run test:ci || npm run test",
"posttag": "[ \"$NODE_ENV\" = \"production\" ] && npm publish || echo 'Skipping publish in non-production'",
"postcommit": "[ -f \"deploy.sh\" ] && ./deploy.sh || echo 'No deploy script found'"
}
}Hook with Custom Script Files:
{
"scripts": {
"prebump": "./scripts/pre-release-check.sh",
"postbump": "node scripts/build-and-test.js",
"postchangelog": "python scripts/update-changelog.py",
"posttag": "./scripts/deploy-release.sh $npm_package_version"
}
}Hook scripts can influence standard-version behavior through their output.
/**
* Special hook output behaviors:
*
* prebump hook output:
* - If prebump script outputs text, it overrides --release-as option
* - Output should be: major, minor, patch, or specific version number
*
* All hooks:
* - stdout is captured and can be logged
* - stderr is displayed immediately
* - Non-zero exit code stops release process
*/Usage Examples:
#!/bin/bash
# prebump hook that determines release type based on commit analysis
if git log --oneline -1 | grep -q "BREAKING CHANGE"; then
echo "major"
elif git log --oneline -1 | grep -q "feat:"; then
echo "minor"
else
echo "patch"
fi// Node.js prebump script
const { execSync } = require('child_process');
// Analyze commits to determine version bump
const commits = execSync('git log --oneline --since="1 week ago"', { encoding: 'utf8' });
if (commits.includes('BREAKING CHANGE') || commits.includes('!:')) {
console.log('major');
} else if (commits.includes('feat:')) {
console.log('minor');
} else {
console.log('patch');
}Proper error handling patterns for lifecycle hooks.
/**
* Hook error handling:
* - Script exit code 0: Success, continue release process
* - Script exit code non-zero: Failure, abort release process
* - Uncaught exceptions in Node.js hooks: Abort release process
* - Empty or missing script: No-op, continue release process
*/Usage Examples:
#!/bin/bash
# Robust prebump hook with error handling
set -e # Exit on any error
echo "Running pre-bump validations..."
# Run tests with proper error handling
if ! npm run test; then
echo "Tests failed, aborting release"
exit 1
fi
# Check for uncommitted changes
if [ -n "$(git status --porcelain)" ]; then
echo "Working directory not clean, aborting release"
exit 1
fi
echo "All validations passed"
exit 0// Node.js hook with error handling
const { execSync } = require('child_process');
try {
console.log('Running build and validation...');
execSync('npm run build', { stdio: 'inherit' });
execSync('npm run test:build', { stdio: 'inherit' });
console.log('Build and validation successful');
process.exit(0);
} catch (error) {
console.error('Build or validation failed:', error.message);
process.exit(1);
}Patterns for using hooks effectively in continuous integration environments.
{
"scripts": {
"prerelease": "[ \"$CI\" != \"true\" ] && echo 'Running in development mode' || echo 'Running in CI mode'",
"prebump": "[ \"$CI\" = \"true\" ] && npm ci || npm install",
"postbump": "[ \"$CI\" = \"true\" ] && npm run build:ci || npm run build:dev",
"posttag": "[ \"$CI\" = \"true\" ] && [ \"$BRANCH\" = \"main\" ] && npm publish || echo 'Skipping publish'"
}
}Install with Tessl CLI
npx tessl i tessl/npm-standard-version