CI/Local Environment Parity Guide
Overview
This guide explains how we ensure consistency between local development and CI environments to prevent “works on my machine” issues.🎯 Key Components
1. Node.js Version Locking (.nvmrc
)
We use a .nvmrc
file to lock the Node.js version across all environments:
- TypeScript compilation
- YAML serialization
- Prettier formatting
- Package resolution
2. Local CI Simulation (npm run ci:local
)
Before pushing code, run the same checks that CI will run:
- ✅ Verifies Node.js version matches
.nvmrc
- ✅ Performs clean install (
npm ci
) - ✅ Runs build process (including OpenAPI generation)
- ✅ Executes all linters
- ✅ Runs all tests
- ✅ Checks for OpenAPI drift
- ✅ Performs security audit
3. Pre-Push Protection
Git hooks automatically run CI checks before pushing:4. CI Configuration
All GitHub Actions workflows use.nvmrc
for Node version:
🚨 Common Issues and Solutions
Issue: “OpenAPI drift detected”
Cause: Generated OpenAPI differs from committed version. Solution:Issue: “Node version mismatch”
Cause: Local Node version doesn’t match.nvmrc
.
Solution:
Issue: “Prettier formatting errors”
Cause: Different Node/Prettier versions format differently. Solution:📋 Checklist for New Developers
- Install
nvm
(Node Version Manager) - Run
nvm use
in the project directory - Run
npm ci
(notnpm install
) - Test with
npm run ci:local
- Enable git hooks with
npx husky install
🔧 Best Practices
- Always use
npm ci
in scripts - Nevernpm install
in CI/automation - Update
.nvmrc
when upgrading Node - Keep it in sync with CI - Run
ci:local
before creating PRs - Catch issues early - Don’t skip pre-push hooks frequently - They’re there to help
- Keep dependencies locked - Commit
package-lock.json
changes
🚀 Quick Commands
📊 Environment Validation
Run this to validate your environment:🔍 Debugging CI Failures
If CI passes locally but fails in GitHub Actions:- Check the exact Node version in CI logs
- Ensure you’re using
npm ci
notnpm install
- Verify no uncommitted changes with
git status
- Run
npm run ci:local
one more time - Compare your package-lock.json with the one in the PR