onevcat/Kingfisher
A lightweight, pure-Swift library for downloading and caching images from the web.
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5d ago
- ✓8 active contributors
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Single-maintainer risk — top contributor 90% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/onevcat/kingfisher)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/onevcat/kingfisher on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: onevcat/Kingfisher
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/onevcat/Kingfisher shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 5d ago
- 8 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Single-maintainer risk — top contributor 90% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live onevcat/Kingfisher
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/onevcat/Kingfisher.
What it runs against: a local clone of onevcat/Kingfisher — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in onevcat/Kingfisher | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 35 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of onevcat/Kingfisher. If you don't
# have one yet, run these first:
#
# git clone https://github.com/onevcat/Kingfisher.git
# cd Kingfisher
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of onevcat/Kingfisher and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "onevcat/Kingfisher(\\.git)?\\b" \\
&& ok "origin remote is onevcat/Kingfisher" \\
|| miss "origin remote is not onevcat/Kingfisher (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "Sources/Kingfisher/Kingfisher.swift" \\
&& ok "Sources/Kingfisher/Kingfisher.swift" \\
|| miss "missing critical file: Sources/Kingfisher/Kingfisher.swift"
test -f "Sources/Kingfisher/ImageCache/ImageCache.swift" \\
&& ok "Sources/Kingfisher/ImageCache/ImageCache.swift" \\
|| miss "missing critical file: Sources/Kingfisher/ImageCache/ImageCache.swift"
test -f "Sources/Kingfisher/Networking/ImageDownloader.swift" \\
&& ok "Sources/Kingfisher/Networking/ImageDownloader.swift" \\
|| miss "missing critical file: Sources/Kingfisher/Networking/ImageDownloader.swift"
test -f "Sources/Kingfisher/General/KingfisherOptions.swift" \\
&& ok "Sources/Kingfisher/General/KingfisherOptions.swift" \\
|| miss "missing critical file: Sources/Kingfisher/General/KingfisherOptions.swift"
test -f "Sources/Kingfisher/SwiftUI/KFImage.swift" \\
&& ok "Sources/Kingfisher/SwiftUI/KFImage.swift" \\
|| miss "missing critical file: Sources/Kingfisher/SwiftUI/KFImage.swift"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 35 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~5d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/onevcat/Kingfisher"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Kingfisher is a pure-Swift library for asynchronous downloading, caching, and displaying images from the web in iOS/macOS/tvOS/watchOS apps. It provides a two-tier hybrid cache (memory + disk), image processors/filters, and convenient extensions for UIImageView, NSImageView, UIButton, and SwiftUI's KFImage component to load remote images with a single line of code. Modular architecture: Core Kingfisher library (pure Swift) at repo root, Demo/ contains a full SwiftUI + UIKit showcase app with separate folders for ViewControllers and SwiftUIViews (including regression tests for past issues). Extensions live in separate namespaces (kf prefix) rather than global scope, isolating Kingfisher logic from Apple frameworks.
👥Who it's for
iOS/macOS developers building apps that display remote images (photo galleries, social feeds, e-commerce) who want to avoid reinventing caching, concurrent downloads, and cache management logic. Also useful for teams needing to replace legacy image libraries while maintaining pure-Swift codebases.
🌱Maturity & risk
Production-ready and actively maintained. The repo has CI/CD (build.yaml and test.yaml workflows), comprehensive feature set (Live Photos, SwiftUI, Swift 6 concurrency), changelog tracking since early versions, and Swift Package Manager support. Last activity visible in workflow configs and extensive demo app suggests active development.
Low risk overall. Single maintainer (onevcat) is a known Swift ecosystem figure, but this concentrates maintenance burden. No obvious version constraints in file list, and broad platform support (iOS/macOS/tvOS/watchOS) means integration is stable. Only minor risk: heavy reliance on URLSession and disk I/O patterns that vary by OS version.
Active areas of work
Active development on Swift 6 and Swift Concurrency strict mode support (noted in README features). Demo app includes recent regression tests (Issue1998View, Issue2035View, Issue2295View, Issue2352View), suggesting ongoing bug fixes and refinements. Workflow files indicate continuous testing across platforms.
🚀Get running
git clone https://github.com/onevcat/Kingfisher.git
cd Kingfisher
# For development: open Kingfisher.xcworkspace in Xcode
# For SPM integration: add to Package.swift or use Xcode 'Add Package Dependency'
# Run demo: open Demo/Demo/Kingfisher-Demo.xcodeproj and build for Simulator
Daily commands:
Open Demo/Demo/Kingfisher-Demo.xcodeproj in Xcode, select a target (iPhone Simulator or physical device), and press Cmd+R. SwiftUI demos are in Demo/Kingfisher-Demo/SwiftUIViews/, UIKit demos in Demo/Kingfisher-Demo/ViewControllers/. All require an internet connection for actual image downloads.
🗺️Map of the codebase
Sources/Kingfisher/Kingfisher.swift— Main entry point and public API; defines KingfisherManager singleton and core download/cache operations every contributor must understandSources/Kingfisher/ImageCache/ImageCache.swift— Core caching layer handling memory and disk persistence; critical for understanding how images are stored and retrievedSources/Kingfisher/Networking/ImageDownloader.swift— Network request orchestration and session management; essential for understanding download flow and retry logicSources/Kingfisher/General/KingfisherOptions.swift— Configuration options enum defining all customization points; required reading for understanding API surfaceSources/Kingfisher/SwiftUI/KFImage.swift— SwiftUI view wrapper providing primary integration point for SwiftUI apps; demonstrates high-level usage patternsSources/Kingfisher/Image/ImageProcessor.swift— Image transformation pipeline architecture; core for understanding image processing and modifier chain pattern
🛠️How to make changes
Add a Custom Image Processor
- Create a new Swift file in Sources/Kingfisher/Image/ that conforms to ImageProcessor protocol (
Sources/Kingfisher/Image/ImageProcessor.swift) - Implement the required
process(item:options:)method returning a UIImage or nil on failure (Sources/Kingfisher/Image/ImageProcessor.swift) - Define a unique identifier string in the protocol conformance (used for cache key generation) (
Sources/Kingfisher/Image/ImageProcessor.swift) - Use in KFImage or UIImageView by passing instance via .processor(.custom(myProcessor)) in options (
Sources/Kingfisher/SwiftUI/KFImage.swift)
Customize Network Requests
- Create a struct conforming to RequestModifier protocol in your code (
Sources/Kingfisher/Networking/RequestModifier.swift) - Implement modify(request:) to mutate URLRequest before sending (e.g., add auth headers) (
Sources/Kingfisher/Networking/RequestModifier.swift) - Pass via KingfisherManager.shared.downloader.requestModifier = yourModifier or per-request via options (
Sources/Kingfisher/Networking/ImageDownloader.swift)
Extend Cache Storage with Custom Backend
- Create a type conforming to CacheStoreProvider protocol to define custom storage location/format (
Sources/Kingfisher/ImageCache/DiskStorage.swift) - Implement read/write methods to integrate custom serialization (e.g., encrypted storage) (
Sources/Kingfisher/ImageCache/DiskStorage.swift) - Pass to ImageCache initializer via diskStorage parameter (
Sources/Kingfisher/ImageCache/ImageCache.swift)
Add a Progress Indicator in SwiftUI
- Use KFImage with the .progressiveJPEG() modifier to receive progress callbacks (
Sources/Kingfisher/SwiftUI/KFImage.swift) - Attach .onProgress(action:) to KFImage to update @State progress value (
Sources/Kingfisher/SwiftUI/KFImage.swift) - Overlay a ProgressView bound to your progress state (
Demo/Demo/Kingfisher-Demo/SwiftUIViews/ProgressiveJPEGDemo.swift)
🔧Why these technologies
- Pure Swift (no C/Objective-C dependencies) — Aligns with modern Swift ecosystem, enables easy distribution via SPM, and simplifies maintenance across iOS/macOS/tvOS
- NSCache + DiskStorage dual-tier caching — NSCache provides automatic memory management under pressure; disk storage persists across app launches and survives memory warnings
- URLSession with custom URLSessionDelegate — Native iOS networking stack avoids third-party HTTP dependencies, integrates with system TLS/certificate validation, and respects URL caching policies
- SwiftUI KFImage + UIKit extensions (dual API) — Supports both modern SwiftUI and legacy UIKit codebases without forcing migration; KFImage provides reactive bindings
- Processor/Modifier composition pattern — Allows chaining transformations (resize → round → filter) without creating intermediate images; improves memory efficiency
⚖️Trade-offs already made
-
Synchronous disk I/O on background thread vs. async I/O
- Why: Simpler API and predictable behavior; avoids callback hell in consumer code
- Consequence: May briefly block a background thread during disk reads; mitigated by DispatchQueue.global() and small read sizes
-
LRU eviction for memory cache (NSCache) vs. time-based TTL
- Why: NSCache respects system memory pressure automatically; LRU is well-understood
- Consequence: Cannot guarantee cache lifetime; suitable for images but less control than explicit TTL
-
Single KingfisherManager singleton vs. multiple instances
- Why: Simplifies API and ensures consistent cache/downloader state across app
- Consequence: Less flexibility for tests or multi-tenant scenarios; workaround via dependency injection in advanced use cases
-
Cache key based on source URL + processor identifier vs. content hash
- Why: Faster key generation; avoids reading/hashing image data
- Consequence: Different processors for same URL generate separate cache entries (by design); potential cache fragmentation if many processors
🚫Non-goals (don't propose these)
- Real-time image synchronization or push updates
- Video playback or animation beyond static GIF rendering
- Offline-first architecture (caches only previously downloaded images, no pre-sync)
- Authentication/OAuth integration (delegates to RequestModifier)
- Linux or Windows support (Apple platforms only)
🪤Traps & gotchas
No SPM Package.swift or Podfile shown in top-60 (likely in repo root but not listed); you'll need to check actual build config for deployment target minimums (likely iOS 11+, macOS 10.12+). Demo app uses both Storyboards (Main.storyboard, LaunchScreen.storyboard) and SwiftUI simultaneously; Xcode may warn about deprecated UIKit patterns if you modify UIViewController demos. Image cache eviction policy and disk size limits are not visible in file list—check core library for KingfisherManager configuration. GIF rendering is optional and may require additional frameworks; check GIFViewController.swift imports.
🏗️Architecture
💡Concepts to learn
- Two-tier hybrid cache (memory + disk) — Kingfisher's core value proposition; memory cache is fast but volatile, disk cache is persistent but slower. Understanding the trade-off is essential for tuning cache behavior in your app.
- URLSession-based concurrent downloads with cancelation — Kingfisher automatically deduplicates in-flight requests and allows canceling downloads; you must understand how URLSessionDataTask lifecycle works to debug hung downloads.
- Protocol-based image processor pipeline — Kingfisher's filters and processors are pluggable via protocol conformance (not inheritance); this is how you extend image processing without modifying core library.
- GCD DispatchQueue for cache thread safety — The library uses background queues to avoid blocking the main thread during disk I/O and image decoding; misunderstanding queue dispatch can cause deadlocks in custom extensions.
- Expiration date-based cache invalidation — Kingfisher supports per-image TTL (time-to-live) in cache; understanding expiration policies prevents stale image bugs in long-running apps.
- SwiftUI @StateObject and property wrapper binding — KFImage and related SwiftUI components use property wrappers to manage image fetch lifecycle; incorrect usage can cause memory leaks or lost updates in SwiftUI views.
- Prefetching strategy for collection views — Kingfisher provides a prefetch API to warm the cache before images are displayed; understanding prefetch timing is critical for smooth scrolling performance in large lists.
🔗Related repos
SDWebImage/SDWebImage— The Objective-C predecessor and closest functional equivalent; Kingfisher is the pure-Swift reimplementation for modern codebaseskean/Nuke— Alternative pure-Swift image loading library with different architecture (async/await first); direct competitor with similar feature setonevcat/Kingfisher-SwiftUI— Official companion repo (or extension branch) for advanced SwiftUI patterns and additional UI components built on top of Kingfisher coreapple/swift-coreimage-plugin— Relevant for understanding how Kingfisher's image processors integrate with Apple's CoreImage framework for filtersrealm/realm-swift— Not directly related but commonly paired with Kingfisher in production apps needing both image caching and local data persistence
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for KingfisherManager cache operations
The repo has extensive demo code but lacks visible unit tests for core caching functionality. Given that Kingfisher is a caching library, there should be dedicated tests for cache hit/miss scenarios, cache eviction policies, and concurrent access patterns. This is critical for a production library.
- [ ] Create Tests/KingfisherManagerCacheTests.swift for cache lifecycle operations
- [ ] Add tests for memory cache vs disk cache behavior in Tests/
- [ ] Test cache expiration and invalidation scenarios
- [ ] Add concurrent access tests to verify thread-safety of cache operations
- [ ] Reference the core caching logic in Sources/ (not visible in file list but implied)
Add macOS-specific CI workflow for regression testing
The repo has both iOS and macOS demo apps (Kingfisher-Demo and Kingfisher-macOS-Demo), but only .github/workflows/build.yaml and test.yaml are visible. There's no evidence of macOS-specific testing in the CI pipeline, yet Demo/Demo/Kingfisher-macOS-Demo/ exists as a first-class demo target.
- [ ] Create .github/workflows/macos-test.yaml for macOS build and test validation
- [ ] Add xcodebuild test command for -scheme Kingfisher-macOS-Demo
- [ ] Configure the workflow to run on push/PR to catch macOS-specific regressions
- [ ] Reference Demo/Demo/Kingfisher-macOS-Demo/GIFHeavyViewController.swift and other macOS views in test matrix
Document and add tests for regression issues tracked in Demo/SwiftUIViews/Regression/
The repo has a Regression folder with specific issue views (Issue1998View.swift, Issue2035View.swift, Issue2295View.swift, Issue2352View.swift) but no corresponding test documentation or regression test suite. These should have automated tests to prevent reintroduction.
- [ ] Create Tests/RegressionTests/ directory to mirror regression test cases
- [ ] Add unit tests for Issue1998, Issue2035, Issue2295, and Issue2352 scenarios
- [ ] Document each regression issue in CHANGELOG.md or a new REGRESSION_FIXES.md file
- [ ] Add SwiftUI view snapshot tests or functional tests for each regression demo view
- [ ] Ensure CI runs regression tests on every build to prevent regressions
🌿Good first issues
- Add unit tests for ImageLoader.swift (Demo/Kingfisher-Demo/Resources/ImageLoader.swift). Currently no test file visible; write tests covering custom data provider initialization, error handling, and cache bypass scenarios.: medium
- Document the regression test suite in Demo/Kingfisher-Demo/SwiftUIViews/Regression/. Add a README or docstring explaining which GitHub issues each test file (Issue1998View, Issue2035View, etc.) addresses and how to verify the fix.: easy
- Extend the Demo app with a new SwiftUI view showcasing Low Data Mode support (feature mentioned in README but no demo file visible). Create Demo/Kingfisher-Demo/SwiftUIViews/LowDataModeDemo.swift with visual toggles to test throttled image quality.: medium
⭐Top contributors
Click to expand
Top contributors
- @onevcat — 90 commits
- @dependabot[bot] — 3 commits
- @aronspringfield — 2 commits
- @RomanticD — 1 commits
- @friday-refined — 1 commits
📝Recent commits
Click to expand
Recent commits
77173fa— Merge pull request #2526 from onevcat/fix/nocilla-thread-safe-stubs (onevcat)52456ca— Use absolute URLs in alternative source tests (onevcat)0f4fc30— Isolate original cache manager tests (onevcat)60a0bc7— Stabilize retry and manager cancellation tests (onevcat)07be065— Stabilize alternative source cancellation test (onevcat)4271201— Avoid appending callbacks to completed downloads (onevcat)fb955e1— Wait for session delegate test completion (onevcat)30a1a63— Make async cancellation latch synchronous (onevcat)b9ab448— Fix async download cancellation race (onevcat)b9b2f12— Fix flaky Nocilla test stubs (onevcat)
🔒Security observations
The Kingfisher repository demonstrates a generally secure posture for an open-source image caching library. No critical vulnerabilities were identified in the visible file structure. The main security considerations are: (1) ensuring HTTPS enforcement and App Transport Security configuration in production, (2) implementing URL validation to prevent cache poisoning, (3) lack of formal security policy documentation, and (4) demo applications using external resources should be carefully controlled. As a library that handles network requests and caching, the core implementation should include proper certificate validation, secure cache management, and input validation. The project would benefit from explicit security documentation and vulnerability disclosure guidelines.
- Low · Missing HTTPS enforcement in demo app —
Demo/Demo/Kingfisher-Demo/Resources/ImageLoader.swift and various demo ViewControllers. The demo application loads images from the web without explicit verification that HTTPS is enforced. The ImageLoader.swift and various demo ViewControllers may load images over HTTP, which could expose user data to man-in-the-middle attacks. Fix: Ensure all image URLs in demo and production code use HTTPS. Implement App Transport Security (ATS) configuration in Info.plist to enforce HTTPS by default, allowing HTTP only for specific trusted domains when necessary. - Low · No explicit security policy documentation —
Repository root. The repository lacks a SECURITY.md or security policy file that documents vulnerability disclosure procedures and security best practices for library users. Fix: Create a SECURITY.md file documenting vulnerability reporting procedures, supported versions, and security patch timeline to encourage responsible disclosure. - Low · Demo app may contain sensitive URLs —
Demo/Demo/Kingfisher-Demo/SwiftUIViews/ and Demo/Demo/Kingfisher-Demo/ViewControllers/. Demo ViewControllers reference external image URLs and resources. If these URLs are modified in the future, they could potentially point to untrusted or malicious sources without validation. Fix: Implement URL validation and whitelisting in demo applications. Use only known, trusted image sources for demonstration purposes. - Low · Potential cache poisoning vulnerability —
Core Kingfisher library (not fully visible in file structure). As an image caching library, Kingfisher could potentially be vulnerable to cache poisoning attacks if image URLs are not properly validated or if HTTP responses lack proper cache control headers. Fix: Ensure proper validation of URLs before caching. Implement checks for cache control headers. Validate image data integrity when retrieving from cache. Consider implementing certificate pinning for sensitive image sources.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.