AsyncImage in WWDC26: Native HTTP Caching, Request-Level Control, and Custom Sessions
With the 2027 OS releases (iOS 27, macOS 27, watchOS 27, tvOS 27, visionOS 27), SwiftUI introduces one of the most meaningful upgrades yet to AsyncImage: automatic HTTP caching by default, along with new APIs for fine-grained control when needed.
The goal is simple: less boilerplate, better performance, and optional control when you actually need it.
🚀 Automatic HTTP Caching (No Code Changes Required)
Starting on iOS 27+, AsyncImage(url:) automatically benefits from standard HTTP caching behavior.
This means:
Server cache headers are fully respected (
Cache-Control,ETag, etc.)Previously loaded images can be served directly from cache
No opt-in API is required
No configuration changes are needed
Basic usage (now cache-enabled by default)
AsyncImage(url: imageURL)What changed?
Before: every request could hit the network again depending on implementation details
Now: responses are cached automatically when running on OS 27+
📌 Important notes:
This is runtime behavior, not a compile-time SDK feature
It applies automatically on supported OS versions even for older deployments
No API exists to “enable caching” because it is always on
🔧 New: Request-Based Control with URLRequest
A new initializer gives you full control over the request:
AsyncImage(request: URLRequest(url: imageURL, cachePolicy: .returnCacheDataElseLoad))This allows you to configure:
Cache policy per image
Revalidation behavior
Forced reload strategies
Any additional
URLRequestcustomization
Available cache policies
.useProtocolCachePolicy.returnCacheDataElseLoad.returnCacheDataDontLoad.reloadIgnoringLocalCacheData.reloadRevalidatingCacheData
Example with placeholder
AsyncImage(
request: URLRequest(
url: imageURL,
cachePolicy: .returnCacheDataElseLoad
)
) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
ProgressView()
}
🌐 New: asyncImageURLSession Modifier
Another major addition is the ability to inject a custom URLSession:
.asyncImageURLSession(customSession)
This gives you control over:
Memory cache size
Disk cache size
Global caching strategy
Shared caching across multiple views
🧠 Real-world Example: Optimized Image Gallery
ScrollView(.horizontal) {
LazyHStack(spacing: 20) {
ForEach(imageURLs, id: \.self) { url in
AsyncImage(
request: URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad),
scale: 2
) { image in
image
.resizable()
.scaledToFill()
} placeholder: {
ProgressView()
}
.frame(width: 280, height: 180)
.clipShape(.rect(cornerRadius: 20))
}
}
}
.asyncImageURLSession(.imageCache)
And a custom session setup:
extension URLSession {
static let imageCache: URLSession = {
let cache = URLCache(
memoryCapacity: 20 * 1024 * 1024,
diskCapacity: 100 * 1024 * 1024
)
let config = URLSessionConfiguration.default
config.urlCache = cache
config.requestCachePolicy = .returnCacheDataElseLoad
return URLSession(configuration: config)
}()
}
⚡ What Problem Does This Solve?
Before iOS 27:
Developers had to manage image caching manually
Many apps implemented custom loaders
Cache behavior was inconsistent across implementations
Now:
AsyncImageis cache-aware by defaultCustomization is optional, not required
Most apps can remove custom image loading layers entirely
📊 Feature Summary
FeatureAvailabilityTypeAutomatic HTTP cachingiOS 27+Runtime behaviorAsyncImage(request:)iOS 27+APIasyncImageURLSession(_:)iOS 27+API
🧩 Conclusion
The new AsyncImage moves SwiftUI toward a production-ready image loading system out of the box.
In practice:
80% of apps →
AsyncImage(url:)is now enoughAdvanced apps →
URLRequest+ customURLSessionprovide full control
It’s a clear step toward reducing infrastructure code and making image loading a first-class, cache-aware SwiftUI feature.
