Package Management Strategies

#packages #dependencies #npm #composer #nuget #versioning #security

Last Updated: May 18, 2025 Related: .NET vs Laravel Complete Developer Guide


Quick Navigation


Universal Principles

🎯 Core Package Management Rules

1. Version Consistency

✅ Good: All packages use compatible versions
✅ Good: Document version decisions
✅ Good: Regular updates with testing
❌ Bad: Mixed major versions
❌ Bad: Ignoring security updates
❌ Bad: "It works on my machine" mentality

2. Dependency Minimalism

Principle: Only add packages that provide significant value
- Avoid packages for simple operations you can code yourself
- Prefer established, well-maintained packages
- Consider bundle size impact (especially for frontend)
- Regularly audit and remove unused dependencies

3. Lock File Management

Always commit lock files:
- package-lock.json (npm)
- yarn.lock (yarn)
- packages.lock.json (.NET)
- composer.lock (PHP)

These ensure reproducible builds across environments

🔍 Evaluation Criteria for New Packages

Before Adding Any Package

Red Flags

🚩 No updates in 2+ years
🚩 Many open security issues
🚩 Excessive dependencies
🚩 Poor documentation
🚩 Single maintainer with no backup
🚩 License incompatibility


.NET Package Management (NuGet)

📦 Central Package Management

<!-- Directory.Packages.props at solution root -->
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>
  
  <PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
  <PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
  <PackageVersion Include="Microsoft.AspNetCore.Identity" Version="8.0.0" />
  <PackageVersion Include="Serilog.AspNetCore" Version="7.0.0" />
  <PackageVersion Include="AutoMapper" Version="12.0.1" />
  <PackageVersion Include="FluentValidation" Version="11.7.1" />
  
  <!-- Development only -->
  <PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0" />
  <PackageVersion Include="Moq" Version="4.20.69" />
  <PackageVersion Include="xunit" Version="2.4.2" />
</Project>

<!-- In project files - no versions needed -->
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>
  
  <PackageReference Include="Microsoft.EntityFrameworkCore" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
  <PackageReference Include="AutoMapper" />
</Project>

🔧 NuGet Configuration

<!-- nuget.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="private-feed" value="https://pkgs.dev.azure.com/company/_packaging/internal/nuget/v3/index.json" />
  </packageSources>
  
  <packageRestore>
    <add key="enabled" value="True" />
    <add key="automatic" value="True" />
  </packageRestore>
  
  <config>
    <add key="repositoryPath" value="packages" />
    <add key="defaultPushSource" value="https://api.nuget.org/v3/index.json" />
  </config>
  
  <packageManagement>
    <add key="format" value="1" />
    <add key="disabled" value="False" />
  </packageManagement>
</configuration>

📊 Package Analysis Scripts

# analyze-packages.ps1
param(
    [string]$SolutionPath = ".",
    [switch]$ShowOutdated,
    [switch]$ShowVulnerable
)

Write-Host "=== Package Analysis Report ===" -ForegroundColor Green

# Find all project files
$projects = Get-ChildItem -Path $SolutionPath -Recurse -Filter "*.csproj"

foreach ($project in $projects) {
    Write-Host "`n--- $($project.Name) ---" -ForegroundColor Yellow
    
    # Show packages
    Set-Location $project.Directory
    dotnet list package --framework net8.0
    
    if ($ShowOutdated) {
        Write-Host "Outdated packages:" -ForegroundColor Red
        dotnet list package --outdated
    }
    
    if ($ShowVulnerable) {
        Write-Host "Vulnerable packages:" -ForegroundColor Red
        dotnet list package --vulnerable
    }
}

# Global package analysis
Write-Host "`n=== Solution-wide Analysis ===" -ForegroundColor Green
Set-Location $SolutionPath

# Check for version conflicts
Write-Host "Checking for version conflicts..."
dotnet restore --verbosity quiet
if ($LASTEXITCODE -ne 0) {
    Write-Host "⚠️  Restore issues detected. Check for version conflicts." -ForegroundColor Red
}

# Generate dependency graph (requires dotnet-depends tool)
if (Get-Command "dotnet-depends" -ErrorAction SilentlyContinue) {
    Write-Host "Generating dependency graph..."
    dotnet depends --output dependencies.html
    Write-Host "✅ Dependency graph saved to dependencies.html" -ForegroundColor Green
}

🚀 Automated Package Updates

# .github/workflows/package-updates.yml
name: Package Updates

on:
  schedule:
    - cron: '0 2 * * 1'  # Every Monday at 2 AM
  workflow_dispatch:

jobs:
  update-packages:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '8.0.x'
          
      - name: Install dotnet-outdated
        run: dotnet tool install --global dotnet-outdated-tool
        
      - name: Check for outdated packages
        run: |
          echo "## Outdated Packages" >> $GITHUB_STEP_SUMMARY
          dotnet outdated --output json > outdated.json
          cat outdated.json >> $GITHUB_STEP_SUMMARY
          
      - name: Update packages (minor versions only)
        run: dotnet outdated --upgrade --version-lock Major
        
      - name: Run tests
        run: dotnet test
        
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v5
        with:
          title: 'chore: Update NuGet packages'
          body: |
            Automated package updates for minor versions only.
            
            Please review the changes and run additional tests if needed.
          branch: automated/package-updates

PHP Package Management (Composer)

🎼 Composer Best Practices

{
    "name": "company/project",
    "description": "Project description",
    "type": "project",
    "keywords": ["laravel", "php"],
    "license": "proprietary",
    "require": {
        "php": "^8.1",
        "laravel/framework": "^10.0",
        "guzzlehttp/guzzle": "^7.2",
        "laravel/sanctum": "^3.2",
        "laravel/tinker": "^2.8"
    },
    "require-dev": {
        "fakerphp/faker": "^1.9.1",
        "laravel/pint": "^1.0",
        "laravel/sail": "^1.18",
        "mockery/mockery": "^1.4.4",
        "nunomaduro/collision": "^7.0",
        "phpunit/phpunit": "^10.1",
        "spatie/laravel-ignition": "^2.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ],
        "test": "phpunit",
        "test-coverage": "phpunit --coverage-html coverage",
        "analyse": "phpstan analyse",
        "format": "pint"
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

🔒 Composer Security

# Security audit
composer audit

# Check for known security vulnerabilities
composer require --dev roave/security-advisories:dev-latest

# This package prevents installation of packages with known security issues

# Update composer.json to include:
"require-dev": {
    "roave/security-advisories": "dev-latest"
}

# Local security checker (alternative)
composer require --dev enlightn/security-checker
vendor/bin/security-checker security:check

📦 Private Package Repository

// composer.json
{
    "repositories": [
        {
            "type": "composer",
            "url": "https://composer.company.com"
        },
        {
            "type": "vcs",
            "url": "https://github.com/company/private-package"
        }
    ],
    "require": {
        "company/private-package": "^1.0"
    }
}

// For GitLab/GitHub private repos
{
    "repositories": [
        {
            "type": "vcs",
            "url": "git@gitlab.company.com:packages/internal-tools.git"
        }
    ]
}

// Authentication setup
composer config --global gitlab-oauth.gitlab.company.com YOUR_TOKEN

🛠️ Composer Scripts and Automation

{
    "scripts": {
        "fresh": [
            "@php artisan migrate:fresh --seed",
            "@php artisan storage:link"
        ],
        "ide-helper": [
            "@php artisan ide-helper:generate",
            "@php artisan ide-helper:models --nowrite"
        ],
        "quality": [
            "pint --test",
            "phpstan analyse",
            "@test"
        ],
        "deploy": [
            "composer install --optimize-autoloader --no-dev",
            "@php artisan config:cache",
            "@php artisan route:cache",
            "@php artisan view:cache"
        ]
    }
}

# Usage
composer run fresh
composer run quality
composer run deploy

JavaScript Package Management (npm/yarn)

📋 Package.json Best Practices

{
  "name": "@company/frontend-app",
  "version": "1.0.0",
  "private": true,
  "description": "Frontend application",
  "keywords": ["react", "typescript", "vite"],
  "author": "Company Name <dev@company.com>",
  "license": "UNLICENSED",
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "typescript": "^5.0.0",
    "@types/react": "^18.2.0",
    "@types/react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^4.0.0",
    "vite": "^4.4.0",
    "eslint": "^8.45.0",
    "prettier": "^3.0.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/jest-dom": "^5.16.4",
    "vitest": "^0.34.0"
  },
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage",
    "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "lint:fix": "eslint src --ext ts,tsx --fix",
    "format": "prettier --write src",
    "type-check": "tsc --noEmit",
    "analyze": "npm run build && npx vite-bundle-analyzer",
    "clean": "rm -rf node_modules dist",
    "reinstall": "npm run clean && npm install"
  },
  "peerDependencies": {
    "react": ">=17.0.0"
  }
}

🔧 NPM Configuration

# .npmrc
# Registry configuration
registry=https://registry.npmjs.org/
@company:registry=https://npm.company.com/

# Security and cache settings
audit-level=high
fund=false
save-exact=true
package-lock=true

# Performance
prefer-offline=true
cache-max=3600000

# Private package authentication (if needed)
//npm.company.com/:_authToken=${NPM_TOKEN}

# Node version enforcement
engine-strict=true

🔍 Package Auditing

# Security audit
npm audit
npm audit --audit-level high
npm audit fix

# Check for outdated packages
npm outdated
npm outdated --depth=0

# Update packages
npm update
npx npm-check-updates -u  # Update to latest versions

# Bundle analysis
npx webpack-bundle-analyzer build/static/js/*.js
npx vite-bundle-analyzer

# Dependency analysis
npx depcheck  # Find unused dependencies
npx license-checker  # Check licenses

🚀 Yarn Berry (v3+) Setup

# .yarnrc.yml
yarnPath: .yarn/releases/yarn-3.6.0.cjs
nodeLinker: node-modules
enableGlobalCache: true
compressionLevel: mixed

plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
  - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs

packageExtensions:
  # Fix peer dependency issues
  react-scripts@*:
    peerDependencies:
      typescript: "*"

# Workspaces configuration
workspaces:
  - "packages/*"
  - "apps/*"

🏗️ Monorepo Package Management

// Root package.json
{
  "name": "@company/monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "scripts": {
    "build": "lerna run build",
    "test": "lerna run test",
    "lint": "lerna run lint",
    "clean": "lerna run clean",
    "version": "lerna version",
    "publish": "lerna publish",
    "bootstrap": "lerna bootstrap"
  },
  "devDependencies": {
    "lerna": "^7.0.0",
    "@lerna/run": "^7.0.0"
  }
}

// lerna.json
{
  "version": "independent",
  "npmClient": "npm",
  "command": {
    "bootstrap": {
      "hoist": true
    },
    "version": {
      "allowBranch": ["main", "develop"],
      "conventionalCommits": true,
      "message": "chore(release): publish",
      "registry": "https://registry.npmjs.org"
    }
  },
  "packages": [
    "packages/*",
    "apps/*"
  ]
}

Security Best Practices

🔒 Universal Security Measures

1. Automated Security Scanning

# .NET
dotnet list package --vulnerable
dotnet list package --deprecated

# PHP
composer audit
vendor/bin/security-checker security:check

# JavaScript
npm audit
yarn audit
npx audit-ci --moderate

# GitHub Actions
- name: Security Audit
  run: |
    npm audit --audit-level high
    composer audit
    dotnet list package --vulnerable

2. Dependency License Compliance

# JavaScript license checking
npx license-checker --summary
npx license-checker --onlyAllow "MIT;Apache-2.0;BSD;ISC"

# .NET license checking (custom PowerShell)
function Check-PackageLicenses {
    $packages = dotnet list package --include-transitive --format json | ConvertFrom-Json
    foreach ($package in $packages.projects.frameworks.topLevelPackages) {
        Write-Host "$($package.id): $($package.resolvedVersion)"
        # Check license URL or metadata
    }
}

# PHP license checking
composer licenses
composer show --self | grep license

3. Supply Chain Security

# GitHub Dependabot configuration
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    reviewers:
      - "security-team"
    assignees:
      - "lead-developer"
    commit-message:
      prefix: "deps"
      include: "scope"
    
  - package-ecosystem: "composer"
    directory: "/"
    schedule:
      interval: "weekly"
    
  - package-ecosystem: "nuget"
    directory: "/"
    schedule:
      interval: "weekly"

🛡️ Security Policies

# Security Policy Template

## Supported Versions
| Version | Supported |
|---------|-----------|
| 2.x.x   | ✅        |
| 1.x.x   | ❌        |

## Dependency Security Requirements
1. All dependencies must be regularly updated
2. No packages with known high/critical vulnerabilities
3. License compatibility verification required
4. Security audit before each release

## Reporting Security Issues
- Create private GitHub security advisory
- Email security@company.com
- Include: affected versions, impact assessment, reproduction steps

## Response Timeline
- Acknowledgment: 48 hours
- Initial assessment: 1 week
- Fix deployment: Based on severity

Automation & CI/CD

🔄 Automated Package Management Pipeline

# .github/workflows/package-management.yml
name: Package Management

on:
  schedule:
    - cron: '0 2 * * 1'  # Weekly on Monday
  pull_request:
    paths:
      - 'package.json'
      - 'composer.json'
      - '*.csproj'
      - 'Directory.Packages.props'
  workflow_dispatch:

jobs:
  audit:
    name: Security Audit
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'
          
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '8.0.x'
          
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
          
      - name: Install Composer
        run: curl -sS https://getcomposer.org/installer | php
        
      - name: JavaScript Security Audit
        run: |
          npm ci
          npm audit
          
      - name: PHP Security Audit
        run: |
          php composer.phar install
          php composer.phar audit
          
      - name: .NET Security Audit
        run: |
          dotnet restore
          dotnet list package --vulnerable
          
  update-check:
    name: Check for Updates
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Check outdated packages
        run: |
          echo "## Package Updates Available" >> $GITHUB_STEP_SUMMARY
          echo "### JavaScript" >> $GITHUB_STEP_SUMMARY
          npm outdated >> $GITHUB_STEP_SUMMARY || true
          echo "### PHP" >> $GITHUB_STEP_SUMMARY
          php composer.phar outdated >> $GITHUB_STEP_SUMMARY || true
          echo "### .NET" >> $GITHUB_STEP_SUMMARY
          dotnet list package --outdated >> $GITHUB_STEP_SUMMARY || true

🏗️ Package Build and Publish

name: Package Release

on:
  push:
    tags:
      - 'v*'

jobs:
  publish-npm:
    if: contains(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          registry-url: 'https://registry.npmjs.org'
          
      - name: Install dependencies
        run: npm ci
        
      - name: Run tests
        run: npm test
        
      - name: Build package
        run: npm run build
        
      - name: Publish to npm
        run: npm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
  
  publish-nuget:
    if: contains(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '8.0.x'
          
      - name: Restore dependencies
        run: dotnet restore
        
      - name: Run tests
        run: dotnet test
        
      - name: Pack NuGet package
        run: dotnet pack --configuration Release --no-restore --output ./packages
        
      - name: Publish to NuGet
        run: dotnet nuget push ./packages/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

Troubleshooting Guide

🚨 Common Issues and Solutions

Dependency Conflicts

# .NET version conflicts
# 1. Check for conflicting versions
dotnet list package --include-transitive | grep PackageName

# 2. Force specific version in Directory.Packages.props
<PackageVersion Include="ConflictingPackage" Version="1.2.3" />

# 3. Use package downgrade strategy
<PackageReference Include="ConflictingPackage" Version="1.2.3">
  <IncludeAssets>compile; build</IncludeAssets>
</PackageReference>

# PHP autoload conflicts
# 1. Clear Composer cache
composer clear-cache
composer dump-autoload

# 2. Check for duplicate class definitions
composer show --tree | grep ConflictingPackage

# JavaScript peer dependency warnings
# 1. Check peer dependencies
npm ls --depth=0
yarn why package-name

# 2. Fix peer dependencies
npm install --save-peer missing-peer-dependency

Performance Issues

# Large node_modules
# 1. Analyze bundle size
npx webpack-bundle-analyzer
npx source-map-explorer build/static/js/*.js

# 2. Remove unused dependencies
npx depcheck
npm uninstall unused-package

# 3. Use production builds
npm run build --production

# Slow Composer installs
# 1. Use composer optimization
composer install --optimize-autoloader --classmap-authoritative

# 2. Enable parallel downloads
composer global require hirak/prestissimo

# 3. Use Composer 2.x
composer self-update --2

Lock File Issues

# Merge conflicts in lock files
# 1. Delete lock file and reinstall
rm package-lock.json && npm install
rm composer.lock && composer install

# 2. Use lock file conflict resolver
npx npm-merge-driver install
git config merge.ours.driver true

# Out of sync lock files
# 1. Verify lock file integrity
npm ci  # Fails if package.json and lock file don't match
composer validate --strict

# 2. Update lock file only
npm install --package-lock-only
composer update --lock

🔍 Debugging Commands

# .NET package debugging
dotnet list package --include-transitive --format json > packages.json
dotnet restore --verbosity diagnostic > restore.log

# PHP Composer debugging
composer why-not package/name version
composer depends vendor/package
composer show --tree > dependency-tree.txt

# JavaScript npm debugging
npm ls --depth=0 > package-tree.txt
npm config list
npm doctor

# Yarn debugging
yarn why package-name
yarn check --integrity
yarn cache clean

Templates and Checklists

✅ Package Addition Checklist

## Before Adding a New Package

### Research Phase
- [ ] Package necessity assessment
- [ ] Alternative evaluation (build vs buy)
- [ ] License compatibility check
- [ ] Security audit (vulnerabilities, maintainer track record)
- [ ] Performance impact analysis
- [ ] Documentation quality review

### Technical Evaluation
- [ ] Version compatibility with existing stack
- [ ] Dependency tree analysis
- [ ] Bundle size impact (for frontend packages)
- [ ] TypeScript support (for JS packages)
- [ ] Framework compatibility

### Integration
- [ ] Add to dependency management config
- [ ] Update documentation
- [ ] Add to CI/CD security scanning
- [ ] Test in development environment
- [ ] Create usage examples/guidelines

### Post-Installation
- [ ] Team notification and training
- [ ] Monitor for issues in staging
- [ ] Set up update schedule
- [ ] Document decision rationale

📝 Monthly Package Review Template

# Monthly Package Review - [Date]

## Security Updates
- [ ] Run security audits
- [ ] Review vulnerability reports
- [ ] Apply critical security patches
- [ ] Update security scanning rules

## Version Updates
- [ ] Check for outdated packages
- [ ] Test minor version updates
- [ ] Evaluate major version upgrades
- [ ] Update lock files

## Cleanup
- [ ] Remove unused dependencies
- [ ] Archive deprecated packages
- [ ] Optimize bundle sizes
- [ ] Clean up development dependencies

## Performance Review
- [ ] Bundle size analysis
- [ ] Load time impact assessment
- [ ] Memory usage evaluation
- [ ] Build time optimization

## Actions Taken
- Updated packages: [list]
- Removed packages: [list]
- Security fixes applied: [list]
- Performance improvements: [list]

## Next Month's Focus
- [Priority items for next review]


Quick Reference Commands

Analysis Commands

# Security
npm audit --audit-level high
composer audit
dotnet list package --vulnerable

# Outdated packages
npm outdated
composer outdated
dotnet list package --outdated

# Dependencies
npm ls --depth=0
composer show --tree
dotnet list package --include-transitive

Update Commands

# Update package managers
npm update -g npm
composer self-update
dotnet tool update -g dotnet-outdated-tool

# Update packages
npm update
composer update
dotnet outdated --upgrade

Tags

#packages #dependencies #security #automation #npm #composer #nuget #versioning


This guide should be reviewed and updated quarterly to reflect new tools and best practices.