# ZIPFoundation: ZIP Handling in Swift Without Third-Party Dependencies

> ZIPFoundation is an MIT-licensed Swift library for creating, reading and modifying ZIP archives on Apple platforms and Linux. Its API hangs off FileManager, its compression comes from Apple's libcompression, and its defaults are worth reading before you ship.

**weichsel/ZIPFoundation** — Effortless ZIP Handling in Swift

- Repository: https://github.com/weichsel/ZIPFoundation
- Stars: 2,733 · Forks: 397
- Language: Swift
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/weichsel-zipfoundation

## The problem ZIPFoundation solves, and for whom

Swift on Apple platforms ships with no first-party ZIP archive API. Foundation gives you file and directory operations, and Apple's libcompression gives you raw compression primitives, but nothing that assembles those primitives into a ZIP container with its central directory, local file headers and entry metadata. The README states that ZIPFoundation is "a library to create, read and modify ZIP archive files" and that it is "written in Swift and based on Apple's libcompression for high performance and energy efficiency." That sentence is the whole pitch: the container format is the library's job, the compression is the platform's job.

The audience is narrow and identifiable. The README lists iOS 12.0+, macOS 10.11+, tvOS 12.0+, watchOS 2.0+ and visionOS 1.0+, plus Linux with the zlib development package. If you are writing an iOS app that exports a user's documents as a single archive, or a macOS command line tool that unpacks uploads, you are the target reader. If you are writing a server in Go or a desktop tool in Rust, this library is not in your toolchain.

One detail in the feature list is easy to skim past: "No 3rd party dependencies (on Apple platforms, zlib on Linux)." That asymmetry matters. On Apple platforms the compression backend is a system framework, so you are not vendoring a compression library into your app. On Linux you take a zlib dependency, which the requirements section phrases as needing the zlib development package installed.

## How the FileManager extension and libcompression fit together

The public surface described in the README is two methods added as extensions on FileManager: zipItem(at:to:) and unzipItem(at:to:). The README says their behaviour is "modeled after the behavior of the Archive Utility in macOS", which is a design statement about defaults rather than about the ZIP format itself. Archive Utility's habits are what produce the two defaults worth knowing: archives are created without compression unless you ask for it, and a directory source contributes a root entry named after the source's lastPathComponent.

The compression path is where the libcompression claim becomes concrete. The README states that to create compressed archives "the optional compressionMethod parameter has to be set to .deflate." So the data flow is: your Swift code hands URLs to the FileManager extension, the extension walks the source and writes ZIP structures, and the deflate step is delegated to the platform compression framework. On Linux, the same deflate step is served by zlib.

Above the two convenience methods, the README describes a lower tier it calls Advanced Usage: accessing individual entries, creating archives, adding and removing entries, closure based reading and writing, in-memory archives, and progress tracking and cancellation. That tier is the one that matters when the Archive Utility model does not match what you need. In-memory archives in particular imply you can build or read an archive without a file on disk, which is the difference between a library that shells out to a filesystem and one that treats the archive as a stream.

The README does not document the on-disk layout of the ZIP structures the library writes, and it does not describe how entry metadata such as timestamps or permissions is mapped. If you need that level of control, the README is not where you will find it.

## Installing ZIPFoundation with Swift Package Manager and zipping a first file

The README gives three installation routes: Swift Package Manager, Carthage and CocoaPods. Swift Package Manager is the one the README documents first, and it requires adding the package to the dependencies of your Package.swift and referring to it in your target. The README's own example pins the version with .upToNextMajor(from: "0.9.0").

```swift
// swift-tools-version:5.0
import PackageDescription
let package = Package(
    name: "<Your Product Name>",
    dependencies: [
		.package(url: "https://github.com/weichsel/ZIPFoundation.git", .upToNextMajor(from: "0.9.0"))
    ],
    targets: [
        .target(
		name: "<Your Target Name>",
		dependencies: ["ZIPFoundation"]),
    ]
)
```

After editing Package.swift, the README says to fetch the library with swift package resolve. If the dependency resolves, you should see the package appear in your resolved dependencies; if it does not, the failure surfaces as a package resolution error naming the URL or the version constraint.

```bash
$ swift package resolve
```

For a first real use, the README's zipping example builds two URLs from the current working directory, points one at file.txt and the other at archive.zip, and calls zipItem. Note the default: this call produces an uncompressed archive. To get deflate compression you must pass compressionMethod: .deflate, which the README describes but does not show in a code sample.

```swift
let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var sourceURL = URL(fileURLWithPath: currentWorkingPath)
sourceURL.appendPathComponent("file.txt")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("archive.zip")
do {
    try fileManager.zipItem(at: sourceURL, to: destinationURL)
} catch {
    print("Creation of ZIP archive failed with error:\(error)")
}
```

If you are integrating through CocoaPods instead, the README's Podfile snippet uses pod 'ZIPFoundation', '~> 0.9' and is followed by pod install. Carthage users add github "weichsel/ZIPFoundation" ~> 0.9 to a Cartfile and run carthage update --no-build, then drag ZIPFoundation.xcodeproj into the workspace. The repository also ships ZIPFoundation.podspec at the top level, which is the file the CocoaPods route depends on.

## Extraction defaults and the parent directory question

Unzipping follows the same shape as zipping. The README's example creates the destination directory first with createDirectory(at:withIntermediateDirectories:attributes:), then calls unzipItem(at:to:), and the README states that this "recursively extracts all entries within the archive to the destination URL."

```swift
let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var sourceURL = URL(fileURLWithPath: currentWorkingPath)
sourceURL.appendPathComponent("archive.zip")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("directory")
do {
    try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
    try fileManager.unzipItem(at: sourceURL, to: destinationURL)
} catch {
    print("Extraction of ZIP archive failed with error:\(error)")
}
```

The createDirectory call is not decoration. It is in the README's example because the destination has to exist before extraction, and the README does not claim unzipItem creates it for you. Treat that as the contract: create the destination, then extract.

The parent directory behaviour is the asymmetry worth internalising. When zipping a directory, the README says a root entry named after the lastPathComponent of the source is added by default, and that passing shouldKeepParent: false suppresses it. There is no equivalent flag documented for unzipping, because the archive already decided its own entry names at creation time. If you are round-tripping archives between ZIPFoundation and another tool, that default root entry is the first thing that will look different from what you expect.

The README does not document what happens when an archive contains entries whose paths escape the destination, nor does it describe any symlink handling policy. On the evidence available, extraction path safety is something you would have to establish from the Tests directory or from reading Sources/, not from the README.

## Where ZIPFoundation is the wrong choice

The clearest boundary is platform. The README's platform badge and requirements list cover Apple platforms and Linux. Android appears nowhere in the README, in the requirements, or in the repository's topics, which are just swift and zip. Searching for the project alongside Android returns results, but the project itself gives no basis for that pairing. If your target is Android, this library is not it.

The second boundary is format. ZIPFoundation does what its name says. The README describes creating, reading and modifying ZIP archive files and nothing else. If you need tar, gzip streams, 7z or a multi-format abstraction, you are outside the scope the README claims.

The third boundary is the default compression setting. Archives are created without compression unless compressionMethod: .deflate is passed. For an app that exports large text or JSON payloads, shipping uncompressed archives by default is a size problem you will only notice in production if you never read the parameter list. The README states the default plainly, but it is the kind of default that is easy to miss because the simplest example in the README does not set it.

The fourth boundary is documentation depth at the edges. The README says it offers "Complete Documentation" as a feature, but the README text itself stops mid-sentence in the Advanced Usage section as reproduced here, and it does not cover rollback, partial-extraction failure semantics, or concurrent access to the same archive. Those are the questions you would ask before putting the library behind a sync engine. The README does not answer them, and the presence of a Tests directory does not tell you which of those cases are covered.

## ZIPFoundation against SSZipArchive and Marmelroy Zip

The alternatives that come up in searches around this project are SSZipArchive and Marmelroy's Zip. The meaningful difference is where the compression comes from. ZIPFoundation states that it is based on Apple's libcompression and that on Apple platforms it has no third-party dependencies, with zlib only on Linux. SSZipArchive is a well-known Objective-C wrapper around minizip, which means a bundled C compression implementation rather than the platform framework. Marmelroy's Zip is a Swift wrapper over minizip as well.

That difference has practical consequences. A minizip-backed library carries its own compression code, which can mean a different set of behaviours across platform versions but also a consistent one. A libcompression-backed library inherits whatever the platform framework does, which is the trade the README is advertising with the phrase "high performance and energy efficiency." Neither approach is automatically better; they are different bets about where you want the compression implementation to live.

The second difference is API shape. ZIPFoundation hangs its two convenience methods off FileManager, so zipping and unzipping read like filesystem operations and follow Archive Utility's conventions. The README also exposes a lower tier for entry-level access, in-memory archives, and progress tracking with cancellation. If your requirement is a single call that produces a file on disk, the FileManager extension is the shortest path. If your requirement is streaming entries in and out with progress reporting, you are in the Advanced Usage tier regardless of which library you pick, and the comparison should be made there rather than at the convenience-method level.

The README does not benchmark ZIPFoundation against either alternative, so any performance comparison would have to come from your own measurements on your own payloads.

## Licence, releases and what upgrading costs

ZIPFoundation is MIT licensed, and the repository carries a LICENSE file at the top level alongside CHANGELOG.md. MIT is permissive: it permits use in closed-source products provided the copyright notice and permission notice are retained. That is a description of the licence text, not legal advice, and if your organisation has a policy on attribution or on distributing licence notices inside an app bundle, that policy is what governs.

The release cadence visible in the repository is uneven. Version 0.9.18 landed on 2024-01-27, 0.9.19 on 2024-04-03, and 0.9.20 on 2025-09-24. The gap between 0.9.19 and 0.9.20 is roughly seventeen months. The last push to the repository was on 2026-09-12, which is recent, but the version history shows that a long quiet period between releases is normal here rather than exceptional. Plan upgrades around releases, not around commit activity.

The version constraint in the README's own examples is .upToNextMajor(from: "0.9.0") for Swift Package Manager, ~> 0.9 for Carthage and ~> 0.9 for CocoaPods. All three express the same intent: accept 0.9.x, do not accept 1.0. Because the project is still on 0.9.x, a minor bump is the only kind of bump that can occur, and there is no 1.0 to signal a stability commitment. Whether a given 0.9.x release changes behaviour is a question for CHANGELOG.md, which the repository includes but the README does not summarise.

The upgrade cost itself is low by construction. The library has no third-party dependencies on Apple platforms, so there is no transitive dependency graph to reconcile when you bump the version. On Linux, the zlib development package is the one external requirement to keep present in your build image. The repository also ships several Package manifest variants at the top level, including Package@swift-4.0.swift, Package@swift-4.1.swift, Package@swift-4.2.swift and Package@swift-5.9.swift, which is the mechanism by which older toolchains are supported. If you are on an older Swift version, that is where the compatibility lives.

## Conclusion

Adopt ZIPFoundation if you are building for iOS, macOS, tvOS, watchOS, visionOS or Linux and want ZIP creation and extraction without a third-party compression dependency on Apple platforms, and if you can live with the stated minimums (iOS 12.0+, macOS 10.11+, Xcode 11.0, Swift 4.0). Do not adopt it for Android: the repository gives no Android support, and the related searches that pair the project name with Android have nothing behind them here. Do not adopt it if you need archive formats other than ZIP, or if you need the framework's own README to spell out extraction safety, because it does not. Before wiring it into a release build, check three things in the repository: whether the 0.9.20 release from 2025-09-24 carries behaviour changes against 0.9.19, what the Tests directory covers for the entry-level API you intend to call, and whether the default of uncompressed output is acceptable for your payload sizes, since compression only happens when you pass .deflate.

## FAQ

### How do I unzip a file with ZIPFoundation?

The README documents FileManager.unzipItem(at:to:), which recursively extracts all entries in the archive to the destination URL. The README's example creates the destination directory with createDirectory(at:withIntermediateDirectories:attributes:) before calling unzipItem.

### What does ZIPFoundation actually do?

The README states that it is a library to create, read and modify ZIP archive files, written in Swift and based on Apple's libcompression. It exposes zipItem and unzipItem as extensions on FileManager, with a lower tier for entry-level access, in-memory archives and progress tracking.

### Does ZIPFoundation compress archives by default?

No. The README states that archives are created without any compression by default, and that the optional compressionMethod parameter has to be set to .deflate to produce compressed ZIP archives.

### Which platforms does ZIPFoundation support?

The README lists iOS 12.0+, macOS 10.11+, tvOS 12.0+, watchOS 2.0+ and visionOS 1.0+, plus Linux with the zlib development package. Android is not listed anywhere in the README or the repository's topics.

### How do I install ZIPFoundation in an Xcode project?

The README gives three routes: Swift Package Manager via a .package entry in Package.swift, Carthage via a Cartfile entry followed by carthage update --no-build, and CocoaPods via pod 'ZIPFoundation', '~> 0.9' followed by pod install.

## Sources

- [Issues](https://github.com/weichsel/ZIPFoundation/issues)
- [License: MIT](https://github.com/weichsel/ZIPFoundation/blob/development/LICENSE)
- [README](https://github.com/weichsel/ZIPFoundation/blob/development/README.md)
- [Releases](https://github.com/weichsel/ZIPFoundation/releases)
- [weichsel/ZIPFoundation on GitHub](https://github.com/weichsel/ZIPFoundation)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/weichsel-zipfoundation
