# Node.js v16 to v20 Upgrade Plan
## Project Overview
- **Current Version**: Node.js v16 with npm v8
- **Target Version**: Node.js v20 with npm v10
- **Application Type**: Full-stack web application with Express.js backend and Next.js frontend
- **Key Technologies**: Express.js, Next.js, MongoDB (Mongoose), Sass, TypeScript
## Executive Summary
This upgrade involves a two-step process (v16 → v18 → v20) due to significant breaking changes, particularly around OpenSSL, crypto APIs, and package compatibility. The main challenges are legacy dependencies and deprecated Node.js APIs.
## Breaking Changes Analysis
### Node.js v16 → v18
- **OpenSSL 3.x upgrade** - Major crypto/TLS changes affecting legacy algorithms
- **Global `fetch()` API** - Experimental but available
- **Stricter crypto behaviors** - Some legacy crypto operations require `--legacy-openssl-provider`
- **V8 engine updates** - Performance improvements but potential compatibility issues
### Node.js v18 → v20
- **Built-in `fetch()` stable** - No longer experimental
- **Updated V8 engine** - Additional performance and security improvements
- **Stricter ES modules support** - Better but potentially breaking CommonJS interactions
- **Enhanced permission model** - `--experimental-permission` flag available
## Critical Dependencies Analysis
### 🚨 BLOCKING Dependencies (Must Upgrade)
#### 1. `mongoose@^4.10.1` → `mongoose@^8.x`
- **Issue**: Version 4.x incompatible with Node.js 18+
- **Breaking Changes**:
- Connection handling changes
- Deprecated callback patterns
- Schema validation changes
- **Migration Effort**: HIGH - Requires code refactoring
#### 2. `node-sass@^9.0.0` → `sass@^1.74.1` (Already Updated in React App)
- **Issue**: Native bindings incompatible with Node.js 18+
- **Status**: ✅ Backend still uses `node-sass`, frontend already migrated to `sass`
- **Action**: Migrate backend build process to use `sass`
#### 3. `fs-promise@^1.0.0` → Native `fs.promises`
- **Issue**: Package deprecated, incompatible with modern Node.js
- **Migration**: Replace with native `fs.promises` API
#### 4. `request-promise@^4.1.1` → `node-fetch` or `undici`
- **Issue**: Built on deprecated `request` package
- **Migration**: Replace with modern HTTP client
### ⚠️ HIGH PRIORITY Dependencies (Should Upgrade)
#### 1. `express@^4.14.0` → `express@^4.19.x`
- **Issue**: Security vulnerabilities in older versions
- **Compatibility**: Should work but needs testing
#### 2. `sequelize@^5.22.5` → `sequelize@^6.x`
- **Issue**: Deprecated APIs, better Node.js 20 support in v6
- **Migration Effort**: MEDIUM
#### 3. `connect-mongo@^2.0.3` → `connect-mongo@^5.x`
- **Issue**: Session store compatibility with newer Node.js versions
### 🔍 MODERATE PRIORITY Dependencies
#### Storybook Dependencies (React App)
- Currently on v7.x - consider upgrading to v8.x for better Node.js 20 support
- Most dependencies already compatible
## Code Pattern Analysis
### Deprecated Patterns Found
#### 1. Buffer Constructor Usage
```javascript
// ❌ Deprecated pattern (if found)
Buffer(size)
Buffer(string, encoding)
// ✅ Modern pattern
Buffer.alloc(size)
Buffer.from(string, encoding)
```
#### 2. Crypto API Usage
- **Location**: `src/lib/ProofOfWorkOnLogin/md5.js`, `crypto-js` package usage
- **Risk**: Potential compatibility issues with OpenSSL 3.x
- **Action**: Test crypto operations thoroughly
#### 3. Callback-based Async Patterns
- **Location**: Throughout MongoDB operations with Mongoose v4
- **Action**: Migrate to Promise-based or async/await patterns
## Implementation Plan
### Phase 1: Preparation & Risk Mitigation (Week 1-2)
#### Step 1.1: Environment Setup
```bash
# Create Node.js version testing branch
git checkout -b node-upgrade-testing
# Install Node Version Manager if not present
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Install Node.js versions for testing
nvm install 18.20.4 # Latest LTS v18
nvm install 20.15.1 # Latest LTS v20
```
#### Step 1.2: Dependency Audit
```bash
# Check for vulnerabilities
npm audit
# Check for outdated packages
npm outdated
# Analyze dependency tree
npm ls --depth=0
```
#### Step 1.3: Critical Dependency Upgrades
**Replace `fs-promise`:**
```bash
npm uninstall fs-promise
# Update code to use native fs.promises
```
**Replace `request-promise`:**
```bash
npm uninstall request-promise request
npm install node-fetch@^2.7.0 # or undici for Node.js 18+
```
**Upgrade Mongoose:**
```bash
npm install mongoose@^8.5.0
# Requires significant code changes - see migration guide
```
### Phase 2: Node.js 18 Migration (Week 3-4)
#### Step 2.1: Update Engine Requirements
```json
// package.json
{
"engines": {
"node": "18",
"npm": "9"
}
}
```
#### Step 2.2: Test with Node.js 18
```bash
nvm use 18
npm install
npm run test:code:jest
npm run test:code:mocha
npm run build:app
```
#### Step 2.3: Handle OpenSSL Issues
If crypto issues arise:
```bash
# Temporary workaround for legacy crypto
export NODE_OPTIONS="--openssl-legacy-provider"
```
### Phase 3: Node.js 20 Migration (Week 5-6)
#### Step 3.1: Update to Node.js 20
```json
// package.json
{
"engines": {
"node": "20",
"npm": "10"
}
}
```
#### Step 3.2: Leverage New Features
- Replace any remaining fetch polyfills with native `fetch()`
- Update test runners to use Node.js built-in test runner where applicable
#### Step 3.3: Performance Optimization
- Update npm scripts to leverage Node.js 20 performance improvements
- Review and optimize any ES module imports
## Testing Strategy
### 1. Unit Tests
```bash
# Run existing test suites
npm run test:code:jest
npm run test:code:mocha
```
### 2. Integration Tests
```bash
# Test all API endpoints
npm run test:e2e:accountflows
npm run test:e2e:leadflows
npm run test:e2e:otherflows
```
### 3. Build Verification
```bash
# Test all build processes
npm run build:app
npm run build:react-beehive
npm run build:onboarding-checklist
```
### 4. Performance Testing
- Monitor memory usage and startup times
- Compare performance metrics before and after upgrade
- Test under production-like load
## Risk Mitigation
### 1. Rollback Plan
- Maintain Node.js v16 Docker images
- Keep package-lock.json backups
- Document all configuration changes
### 2. Gradual Deployment
- Deploy to staging environment first
- Use feature flags for critical functionality
- Monitor error rates and performance metrics
### 3. Monitoring
- Set up enhanced logging for Node.js version-specific issues
- Monitor crypto operation performance
- Watch for deprecation warnings
## File-Specific Changes Required
### 1. `/checkNodeVersion.js`
Update to accept Node.js 18 and 20:
```javascript
const expectedNodeVersion = process.env.NODE_ENV === 'production' ? '20' : ['18', '20'];
```
### 2. `/.nvmrc`
Update to specify Node.js 20:
```
20.15.1
```
### 3. Build Scripts
Update any hardcoded Node.js version references in:
- Docker files
- CI/CD configurations
- Deployment scripts
## Dependencies Migration Guide
### Mongoose v4 → v8 Migration
**Key Changes:**
- Connection string format changes
- Callback removal (use Promises/async-await)
- Schema validation updates
- Middleware signature changes
**Example Migration:**
```javascript
// ❌ Old (v4)
mongoose.connect(uri, options, callback);
// ✅ New (v8)
await mongoose.connect(uri, options);
```
### Express Middleware Updates
**Helmet Configuration:**
- Update helmet configuration for compatibility
- Review CSP settings for new Node.js features
## Success Criteria
- [ ] All tests passing on Node.js 20
- [ ] No deprecation warnings in logs
- [ ] Performance metrics equal or better than Node.js 16
- [ ] All critical dependencies updated
- [ ] Production deployment successful
- [ ] No regression in functionality
## Post-Upgrade Considerations
### 1. Documentation Updates
- Update development setup documentation
- Revise deployment guides
- Update dependency management processes
### 2. Team Training
- Brief team on new Node.js features
- Document migration learnings
- Update coding standards for new Node.js version
### 3. Future Upgrades
- Establish regular Node.js upgrade schedule
- Monitor Node.js release cycle
- Proactive dependency management strategy
## Security Vulnerabilities to Address
Recent Express.js security releases (September 2024) identified several critical vulnerabilities that may affect your upgrade:
### High Severity
- **CVE-2024-45590** - body-parser DoS vulnerability (upgrade to ≥1.20.3)
- **CVE-2024-47178** - basic-auth-connect timing attack (upgrade to ≥1.1.0)
### Moderate Severity
- **CVE-2024-43796** - Express XSS via response.redirect() (upgrade to ≥4.20.0)
- **CVE-2024-43799** - send utility XSS vulnerability (upgrade to ≥0.19.0)
- **CVE-2024-43800** - serve-static XSS vulnerability (upgrade to ≥1.16.0)
**Action Required**: Verify these vulnerabilities are addressed during the upgrade process.
## Additional Gotchas and Challenges
### 1. Docker and Container Configuration
**Files to Update:**
- `Dockerfile` - Currently uses `FROM node:16-buster`
- `docker-compose.yml` - Service configurations
- `.gitpod.dockerfile` - Gitpod environment still references Node 10.16.2
**Required Changes:**
```dockerfile
# Update Dockerfile
FROM node:20-bookworm # or node:20-alpine for smaller size
# Update .gitpod.dockerfile
ENV NODE_ENGINE 20.15.1
```
### 2. Helmet.js Compatibility
Your app uses `helmet@^3.1.0` which is very outdated. Helmet v7+ has significant breaking changes:
**Current Issues:**
- Helmet v3 may not be compatible with Node.js 20
- Missing newer security headers
- Deprecated API usage
**Required Updates:**
```bash
npm install helmet@^7.1.0
```
**Code Changes Required:**
```javascript
// OLD (v3)
app.use(helmet());
// NEW (v7) - explicit configuration may be needed
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
// ... other directives
},
},
}));
```
### 3. File Upload Security (multiparty)
Found usage of `multiparty@^4.1.3` in `/src/config/express/requests.js`:
**Potential Issues:**
- May have security vulnerabilities with newer Node.js versions
- Stream handling changes in Node.js 18+
**Recommended Actions:**
1. Audit multiparty usage for security issues
2. Consider migrating to `formidable` or `multer`
3. Test file upload functionality thoroughly after upgrade
### 4. Build Tool Compatibility Issues
**Gulp Compatibility:**
- Current Gulp version may have `primordials` errors with Node.js 18+
- Need to verify all Gulp plugins are compatible
**Node-gyp Issues:**
- Python version compatibility (requires Python ≥3.6, ≤3.11 for older node-gyp)
- Native addon compilation for bcrypt, node-sass
- Windows build tools compatibility
### 5. TypeScript Configuration Updates
**Current Setup Analysis:**
- Main project: ES2015 target, CommonJS modules
- React app: ES2017 target, ESNext modules
- Using older TypeScript compilation targets
**Recommended Updates:**
```json
// Update tsconfig.json target for Node.js 20
{
"compilerOptions": {
"target": "ES2022", // Node.js 20 supports ES2022
"lib": ["ES2022"]
}
}
```
### 6. Environment Variable Security
**High Usage of process.env Found:**
- 50+ files directly accessing `process.env`
- No environment variable validation
**Security Recommendations:**
1. Implement environment variable validation using `joi` or `zod`
2. Create centralized environment configuration
3. Avoid exposing sensitive variables in client-side code
### 7. CI/CD Pipeline Updates
**Files to Update:**
- `scripts/codeship/setup.sh` - May reference specific Node.js versions
- GitHub Actions workflows (if any)
- Heroku buildpacks configuration
### 8. Performance Considerations
**Potential Node.js 20 Benefits:**
- ~20% faster startup times
- Improved memory usage
- Better ES modules performance
**Monitoring Required:**
- Watch for memory usage patterns changes
- Monitor CPU usage for crypto operations
- Test WebAssembly performance if used
### 9. Third-Party Service Integrations
**Services Using Node.js-specific Code:**
- Onfido integration
- Revolut/Starling bank integrations
- Trustpilot API calls
- AWS SDK usage
**Action Required:**
- Test all third-party integrations after upgrade
- Verify API client compatibility
- Check for any Node.js version-specific workarounds
### 10. Testing Infrastructure Updates
**Browser Test Configuration:**
- Selenium container may need updates
- WebDriver compatibility with Node.js 20
- Update test runner configurations
## Extended Testing Strategy
### 1. Regression Testing Checklist
- [ ] File upload functionality (multiparty)
- [ ] All third-party API integrations
- [ ] Crypto operations (bcrypt, OTP generation)
- [ ] Database connections (MongoDB, PostgreSQL)
- [ ] Email sending functionality
- [ ] PDF generation (if applicable)
- [ ] Image processing operations
### 2. Performance Baseline Testing
- [ ] Measure startup time before/after
- [ ] Monitor memory usage patterns
- [ ] Test concurrent request handling
- [ ] Benchmark crypto operations
- [ ] Database query performance
### 3. Security Testing
- [ ] Verify Helmet.js headers are correct
- [ ] Test CSP policies still work
- [ ] Validate environment variable access
- [ ] Check for any new deprecation warnings
## Emergency Rollback Plan
### Quick Rollback Steps
1. **Docker Images**: Maintain Node.js 16 images in registry
2. **Package Locks**: Keep backup of `package-lock.json` files
3. **Environment Variables**: Document any changed NODE_OPTIONS
4. **Database**: Ensure no schema changes during upgrade
5. **Monitoring**: Set up alerts for error rate spikes
### Rollback Triggers
- Error rate increase >5%
- Memory usage increase >30%
- Any critical functionality failures
- Third-party integration failures
## BeeHive (Next.js) Integration Complexities
### **Hybrid Architecture Challenges**
Your application has a **unique hybrid setup** where Next.js BeeHive is served as static exports through Express.js middleware:
```typescript
// Express serves static Next.js exports
app.use("/uk", csrfProtection, staticContentReactRoutes);
// Next.js config for static export
const nextConfig = {
output: "export", // Static site generation
rewrites: async () => ({
fallback: [{ source: "/:path*", destination: "http://localhost:3000/:path*" }]
})
};
```
### **Critical Static Export Issues (Node.js 18+)**
1. **SubtleCrypto Edge Runtime Bug**: Node.js 18.17+ breaks `crypto.subtle.importKey()` in Next.js Edge Runtime
- **Impact**: Authentication/JWT processing may fail (need to verify any usage in codebase)
- **Mitigation**: Avoid crypto operations in middleware, use API routes instead
2. **Static Export Compatibility**: Next.js 14 removed `next export` command in favor of `output: 'export'`
- **Your Current Setup**: Already using `output: 'export'` ✅
- **Risk**: Serving mechanism through Express middleware needs validation
3. **Build System Integration**: Next.js static export must work with Express.js static file serving
- **File Path**: `react-beehive/out/` → Express middleware → Production serving
- **Testing Required**: Full build → export → Express integration pipeline
### **POC Upgrade Analysis Integration**
Based on PR #8786 findings, **additional complexities identified**:
#### **ESLint v9 Migration**
```javascript
// New flat config requirement
import { FlatCompat } from '@eslint/eslintrc';
export default [/* flat config objects */];
```
#### **Build System ESM Conversion**
```javascript
// gulpfile.js → gulpfile.mjs with complex ESM/CommonJS interop
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const sass = require('gulp-sass')(require('node-sass')); // Still problematic
```
#### **Incomplete Dependencies in POC**
- `node-sass` still present (blocks ARM64 deployment)
- Mongoose migration not implemented
- `fs-promise` replacement missing
---
## Implementation Timeline
### **Phase 1: Infrastructure Preparation (Weeks 1-2)**
- [ ] **Week 1**: Validate BeeHive static export compatibility with Node.js 18
- [ ] **Week 1**: Test Heroku deployment pipeline with Node.js 18 base image
- [ ] **Week 2**: Complete node-sass → dart-sass migration (blocking for ARM64)
- [ ] **Week 2**: Replace deprecated packages (`fs-promise`, `request-promise`)
### **Phase 2: Core Dependency Updates (Weeks 3-5)**
- [ ] **Week 3**: Mongoose v4 → v8 migration (callback → Promise patterns)
- [ ] **Week 3**: ESLint v9 flat config migration
- [ ] **Week 4**: Express.js middleware and build system updates
- [ ] **Week 5**: Integration testing with BeeHive static export pipeline
### **Phase 3: Node.js 18 Upgrade (Weeks 6-7)**
- [ ] **Week 6**: Node.js v16 → v18 upgrade and compatibility testing
- [ ] **Week 6**: Docker image updates and CI/CD pipeline validation
- [ ] **Week 7**: Staging deployment and performance benchmarking
### **Phase 4: Node.js 20 Preparation (Weeks 8-10)**
- [ ] **Week 8**: Research Node.js 20 specific compatibility issues
- [ ] **Week 9**: Node.js v18 → v20 upgrade in development environment
- [ ] **Week 10**: Production deployment with full monitoring
---
## Risk Assessment
| Risk Category | Impact | Mitigation Strategy |
|---------------|---------|-------------------|
| **BeeHive Static Export** | **HIGH** | Dedicated integration testing, rollback to current serving method |
| **Build System (Gulp/ESM)** | **HIGH** | Incremental migration, maintain fallback build process |
| **SubtleCrypto Edge Runtime** | **MEDIUM** | Move crypto operations to API routes |
| **ESLint v9 Migration** | **MEDIUM** | Phased config migration, lint rule validation |
| **Database Layer (Mongoose)** | **HIGH** | Extensive testing, gradual callback → Promise conversion |
---
## Deployment Validation Checklist
### **BeeHive Integration Tests**
- [ ] Static export builds successfully with Node.js 18/20
- [ ] Express.js serves exported files correctly
- [ ] Client-side routing works in production
- [ ] Storybook builds and deploys properly
### **Performance Benchmarks**
- [ ] Build times remain within 10% of current
- [ ] Bundle sizes don't increase significantly
- [ ] Static file serving latency unchanged
- [ ] Memory usage stays within container limits
### **Security Validation**
- [ ] All high/critical CVEs resolved
- [ ] Crypto operations function correctly
- [ ] Authentication flows remain intact
- [ ] CSRF protection maintained
---
## Additional Resources
- [Node.js v18 Release Notes](https://nodejs.org/en/blog/release/v18.0.0)
- [Node.js v20 Release Notes](https://nodejs.org/en/blog/release/v20.0.0)
- [Next.js Static Export Guide](https://nextjs.org/docs/app/building-your-application/deploying/static-exports)
- [Next.js 14 Migration Guide](https://nextjs.org/docs/app/building-your-application/upgrading/version-14)
- [Mongoose v8 Migration Guide](https://mongoosejs.com/docs/migrating_to_8.html)
- [ESLint v9 Flat Config Migration](https://eslint.org/docs/latest/use/configure/migration-guide)
- [Express.js Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
- [Express.js September 2024 Security Releases](https://expressjs.com/2024/09/29/security-releases.html)
- [Helmet.js v7 Migration Guide](https://helmetjs.github.io/)
- [Node-gyp Troubleshooting Guide](https://github.com/nodejs/node-gyp/blob/main/docs/README.md)