serverless-plugin-artifact-manager
v1.0.6
Published
A serverless plugin that dynamically manages artifactDirectoryName to ensure CloudFormation detects code changes
Maintainers
Readme
Serverless Artifact Directory Manager Plugin
A Serverless Framework plugin that dynamically manages artifactDirectoryName to ensure CloudFormation properly detects Lambda code changes.
🎯 Purpose
When deploying Lambda functions, CloudFormation uses the artifactDirectoryName to determine if there have been code changes. If this path doesn't change between deployments, CloudFormation assumes no code changes occurred and skips the Lambda update - even if your code has actually changed.
This plugin solves that problem by:
- ✅ Generating unique artifact directory names for each deployment
- ✅ Ensuring CloudFormation always detects code changes
- ✅ Supporting multiple naming strategies (timestamp, hash, hybrid)
- ✅ Providing variable resolvers for flexible configuration
📦 Installation
npm install --save-dev serverless-plugin-artifact-directory-manager🚀 Usage
Basic Usage
Add the plugin to your serverless.yml:
plugins:
- serverless-plugin-artifact-directory-manager
package:
excludeDevDependencies: false
individually: ${env:SERVERLESS_WEBPACK_INDIVIDUALLY, false}
artifactDirectoryName: ${artifactDir:fullPath}
patterns:
- "!.vscode/**"
- "!.test/**"
- "!./logo.png"
- "!node_modules/**"Advanced Usage
Configure the plugin behavior:
plugins:
- serverless-plugin-artifact-directory-manager
custom:
artifactDirectoryManager:
strategy: hash # Options: 'hash' (default), 'timestamp', 'hybrid'
includeGitCommit: true # Include git commit hash in directory name
verbose: true # Enable verbose logging
enableCache: true # Enable build caching (default: true for hash/hybrid, false for timestamp)
package:
artifactDirectoryName: ${artifactDir:fullPath}🔧 Configuration Options
Strategy Options
hash(default): Changes only when code changes (most efficient, only rebuilds when necessary)timestamp: Changes with every deployment (guarantees uniqueness but may cause unnecessary rebuilds)hybrid: Combines both approaches for guaranteed uniqueness and change detection
📊 Strategy Tradeoffs
| Strategy | Efficiency | Reliability | Use Case | Pros | Cons |
|----------|------------|-------------|----------|------|------|
| hash ⭐ | 🟢 High | 🟡 Good | Most projects | • Only updates when code changes• Faster deployments• Lower AWS costs• Matches original behavior | • Rare edge cases where CloudFormation needs update but hash doesn't change |
| timestamp | 🔴 Low | 🟢 Perfect | Critical systems | • Guarantees CloudFormation detection• Never misses updates• Simple and predictable | • Updates Lambda on every deploy• Slower deployments• Higher AWS costs• Unnecessary cold starts |
| hybrid | 🟡 Medium | 🟢 Perfect | High-change environments | • Best of both worlds• Content-aware + guaranteed unique• Good for rapid development | • Slightly larger hash• More complex logic• Still updates more than pure hash |
🤔 When to Use Each Strategy
Choose hash (default) when:
- ✅ You want optimal performance and efficiency
- ✅ Your deployments should only update when code actually changes
- ✅ You trust the content-based detection (works for 99% of cases)
- ✅ You want to minimize AWS Lambda update costs
Choose timestamp when:
- ✅ You have critical systems that must never miss an update
- ✅ CloudFormation reliability is more important than efficiency
- ✅ You're debugging deployment issues and want to force updates
- ✅ You have compliance requirements for deployment tracking
Choose hybrid when:
- ✅ You're in rapid development with frequent deployments
- ✅ You want content-awareness but also guaranteed uniqueness
- ✅ You need a balance between efficiency and reliability
- ✅ You're migrating from timestamp and want a safer transition
💡 Pro Tips
- Start with
hash- it's the most efficient and matches your original setup - Use
timestamptemporarily if you suspect deployment detection issues - Consider
hybridfor development environments with frequent changes
Variable Resolvers
The plugin provides several variable resolvers you can use in your serverless.yml:
package:
artifactDirectoryName: ${artifactDir:fullPath} # Full path: serverless/myservice/dev/2024-01-15T10-30-00-abc123def456
# Or use individual components:
custom:
myTimestamp: ${artifactDir:timestamp} # 2024-01-15T10-30-00
myHash: ${artifactDir:hash} # abc123def456
myPrefix: ${artifactDir:prefix} # serverless/myservice/dev
myService: ${artifactDir:service} # myservice
myStage: ${artifactDir:stage} # dev
myRegion: ${artifactDir:region} # us-east-1📋 Commands
Show Plugin Information
serverless artifact-info # Basic info
serverless artifact-info --verbose # Detailed info🏗️ How It Works
- Initialization: The plugin analyzes your project structure and configuration
- Hash Generation: Creates a unique identifier based on your chosen strategy:
- Timestamp: Current deployment time
- Hash: Content hash of source files, dependencies, and configuration
- Hybrid: Combination of both
- Variable Injection: Makes artifact directory variables available throughout your configuration
- Package Update: Automatically updates the
package.artifactDirectoryNameif needed
Hash Calculation Details
The hash and hybrid strategies calculate content hashes from:
✅ Always Included:
package.json- Dependencies and project configurationserverless.yml- Serverless configuration- Source files (
src/**/*.{js,ts,json,yml,yaml}) - Module files (when deploying specific modules)
✅ Conditionally Included:
package-lock.json,yarn.lock,pnpm-lock.yaml- When present- Environment files (
.env,.env-hd,.env.local,.env.production) - When present - Git commit hash - When
includeGitCommit: true
❌ Always Excluded:
node_modules/- Too large and volatile- Hidden directories (
.git/,.vscode/, etc.) - Build artifacts and temporary files
🔍 Example Output
🗂️ Artifact Directory Manager - Configuration Injected
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 Core Properties:
Service: my-api
Stage: dev
Region: us-east-1
📁 Directory Details:
Timestamp: 2024-01-15T10-30-00
Hash: abc123def456
Prefix: serverless/my-api/dev
Full Path: serverless/my-api/dev/2024-01-15T10-30-00-abc123def456
💡 Usage:
Use ${artifactDir:fullPath} in your serverless.yml
Use ${artifactDir:timestamp} for timestamp-only
Use ${artifactDir:hash} for hash-only
Use ${artifactDir:prefix} for prefix-only
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━🐛 Debugging
Enable verbose logging:
export ARTIFACT_DIR_DEBUG=true
serverless deploy --verboseOr use the plugin-specific command:
serverless artifact-info --verbose🔧 Integration with Existing Setup
Replace Existing Configuration
If you're currently using:
package:
artifactDirectoryName: ${file(../../serverless/core/dist/serverless-artifact.js):artifactDirectoryName, file(./dist/serverless-artifact.js):artifactDirectoryName, file(./node_modules/@emerald-works/serverless-core/dist/serverless-artifact.js):artifactDirectoryName}Simply replace with:
plugins:
- serverless-plugin-artifact-directory-manager
package:
artifactDirectoryName: ${artifactDir:fullPath}🚀 Build Caching Optimization
⚡ Intelligent Build Skipping
The plugin includes an intelligent caching system that can dramatically speed up deployments by skipping unnecessary builds and uploads:
custom:
artifactDirectoryManager:
strategy: hash # Required for caching
enableCache: true # Enable build caching (default: true for hash/hybrid)How It Works
- Content Hash Analysis: Before running esbuild, the plugin calculates a content hash of your source files
- Artifact Detection: Checks if artifacts already exist for the current content hash
- Build Skipping: If artifacts exist and content hasn't changed, skips esbuild and packaging entirely
- Artifact Reuse: Points to existing zip files, avoiding redundant S3 uploads
Performance Benefits
- ⚡ Faster Deployments: Skip build when code hasn't changed (30-90% time savings)
- 💰 Lower AWS Costs: Avoid unnecessary S3 uploads and Lambda updates
- 🔋 Reduced CPU Usage: No redundant TypeScript compilation or bundling
- 🌍 Better Developer Experience: Near-instant deployments for infrastructure-only changes
When Caching Activates
✅ Cache Hit: Build skipped, existing artifacts reused
- Source files unchanged (package.json, src/*, serverless.yml)
- Previous successful build exists for this hash
- All required zip files present
❌ Cache Miss: Normal build process continues
- Source code modified since last build
- No previous artifacts found for this hash
- Missing or corrupted artifact files
Configuration Options
custom:
artifactDirectoryManager:
enableCache: true # Enable/disable caching (default: smart)
strategy: 'hash' # Required for caching ('timestamp' disables cache)
includeGitCommit: true # Include git state in cache keySmart Defaults:
hashstrategy: Cache enabled by defaulthybridstrategy: Cache enabled by defaulttimestampstrategy: Cache disabled by default
📈 Benefits
- Guaranteed CloudFormation Detection: Every deployment gets a unique artifact path
- Flexible Strategies: Choose between timestamp, content-hash, or hybrid approaches
- Git Integration: Optionally include git commit hashes
- Easy Migration: Simple drop-in replacement for existing configurations
- Verbose Logging: Detailed information for debugging and verification
- Intelligent Caching: Skip builds when code hasn't changed (hash/hybrid strategies)
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
MIT License - see the LICENSE file for details.
🆘 Support
- Create an issue on GitHub
- Check the verbose output with
--verboseflag - Enable debug logging with
ARTIFACT_DIR_DEBUG=true
