DEV Community

ArshTechPro
ArshTechPro

Posted on

Why SPM Needs a CHANGELOG (And How to Write One)

If you've ever updated a dependency and wondered "Wait, what changed?", you know the pain of packages without proper changelogs. Let's talk about why changelogs matter for Swift Package Manager (SPM) projects and how to write one that developers will actually appreciate.

The Problem

You're maintaining an iOS app that depends on several Swift packages. One releases version 2.0. Should you update? What changed? Will it break your code? You dig through commits, scan PRs, and eventually just... hope for the best.

This is exactly why changelogs exist.

What is a CHANGELOG?

A CHANGELOG is a file (CHANGELOG.md) that documents all notable changes to your package in a human-readable format. It answers one crucial question: "What's different?"

Why It Matters

For Package Users:

  • Decision Making: Should I update now or wait?
  • Migration Planning: What do I need to change in my code?
  • Feature Discovery: Oh, they added that feature I needed!

For Package Maintainers:

  • Communication: Clear way to announce changes
  • Documentation: Historical record of decisions
  • Professionalism: Shows you care about your users

The Standard Format: Keep a Changelog

The iOS/Swift community uses the Keep a Changelog format:

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Dark mode support for all UI components
- New `fetchUserProfile()` async method

### Changed
- Updated minimum iOS version to 15.0

## [2.1.0] - 2025-03-15
### Added
- SwiftUI previews for all public views
- Comprehensive error handling

### Fixed
- Memory leak in image caching layer
- Crash when network request times out

### Security
- Updated dependencies to patch CVE-2025-1234

## [2.0.0] - 2025-02-20
### Changed
- **BREAKING**: Renamed `NetworkManager` to `APIClient`
- **BREAKING**: All completion handlers replaced with async/await

### Removed
- Deprecated iOS 13 support

### Added
- Full async/await support
- Improved error messages
Enter fullscreen mode Exit fullscreen mode

The Six Categories

Added - New features, APIs, or capabilities

### Added
- New `Logger` class for debugging
Enter fullscreen mode Exit fullscreen mode

Changed - Modifications to existing functionality

### Changed
- Improved performance of data parsing (2x faster)
Enter fullscreen mode Exit fullscreen mode

Deprecated - Features that will be removed soon

### Deprecated
- `oldMethod()` - Use `newMethod()` instead. Will be removed in 3.0.0
Enter fullscreen mode Exit fullscreen mode

Removed - Features that are gone

### Removed
- iOS 12 support
Enter fullscreen mode Exit fullscreen mode

Fixed - Bug fixes

### Fixed
- Crash when array is empty
Enter fullscreen mode Exit fullscreen mode

Security - Security patches

### Security
- Fixed potential XSS vulnerability
Enter fullscreen mode Exit fullscreen mode

Practical Workflow

Step 1: Create the File
Add CHANGELOG.md to your package root, next to Package.swift.

Step 2: Add to Unreleased
Every time you make a change, add it under [Unreleased]:

## [Unreleased]
### Fixed
- Fixed typo in error message
Enter fullscreen mode Exit fullscreen mode

Step 3: Release Process
When ready to release:

  1. Move [Unreleased] changes to a new version section
  2. Add the release date
  3. Create a git tag matching the version
## [Unreleased]

## [1.2.0] - 2025-03-20
### Fixed
- Fixed typo in error message
Enter fullscreen mode Exit fullscreen mode

Semantic Versioning

Your changelog works with semantic versioning (SemVer):

Version Format: MAJOR.MINOR.PATCH

  • MAJOR (2.0.0): Breaking changes
  • MINOR (1.5.0): New features, backward compatible
  • PATCH (1.4.1): Bug fixes, backward compatible

Common Mistakes to Avoid

❌ Don't Do This:

### Changed
- Bug fixes and improvements
- Various updates
Enter fullscreen mode Exit fullscreen mode

✅ Do This Instead:

### Fixed
- Fixed crash when user profile image is missing
- Resolved memory leak in WebSocket connection
Enter fullscreen mode Exit fullscreen mode

Be specific! Vague entries help nobody.

Pro Tips

Link to Issues and PRs:

### Fixed
- Fixed memory leak in image cache ([#123](link-to-issue))
Enter fullscreen mode Exit fullscreen mode

Add Migration Guides for Breaking Changes:

## [2.0.0] - 2025-03-20
### Changed
- **BREAKING**: Replaced completion handlers with async/await

### Migration Guide

Before:
client.fetch { result in }

After:
let data = try await client.fetch()
Enter fullscreen mode Exit fullscreen mode

Tag Your Releases:

git tag -a v1.2.0 -m "Release 1.2.0"
git push origin v1.2.0
Enter fullscreen mode Exit fullscreen mode

Getting Started Today

Here's a minimal template:

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.0.0] - 2025-03-20
### Added
- Initial release
- Core networking functionality
- Authentication support
Enter fullscreen mode Exit fullscreen mode

Copy this, replace the content, and you're done!

Take away

A good changelog takes just a few extra minutes per release, but saves hours of confusion for your users.

Top comments (1)

Collapse
 
arshtechpro profile image
ArshTechPro

A CHANGELOG is a file (CHANGELOG.md) that documents all notable changes to your package in a human-readable format.