Putting a LazyVStack or LazyHStack in a ScrollView causes stuttering
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
Stuttering when using LazyVStack or LazyHStack inside a ScrollView is caused by on-demand view creation — as you scroll, SwiftUI creates new cells just-in-time, and if that creation is expensive (complex layouts, image loading, state initialization), it causes frame drops. The primary fixes are to simplify cell views, pre-load images asynchronously, avoid heavy onAppear work, and use fixed-size cells with LazyVStack(spacing:pinnedViews:) so SwiftUI can skip measuring. For large datasets, List (backed by UITableView) often performs better than ScrollView + LazyVStack.
Why Stuttering Happens
The timeline of a stuttering frame:
- User scrolls down
- SwiftUI determines new cells are needed
LazyVStackcreates the cell view body (layout, modifiers, etc.)- SwiftUI measures the cell (calls
sizeThatFits) - SwiftUI renders the cell
If steps 3-5 take more than ~16ms (60 FPS) or ~8ms (120 FPS on ProMotion), the frame drops and scrolling stutters.
Fix 1: Simplify Cell Views
Reduce the complexity of each cell:
Fix 2: Use Fixed-Size Cells
When all cells have the same height, SwiftUI can skip measurement:
Fix 3: Cache Images Properly
AsyncImage starts a new network request each time the cell appears:
Fix 4: Use List Instead of ScrollView + LazyVStack
List uses UITableView under the hood with cell recycling, which is often smoother:
Fix 5: Prefetch Data
Load data before cells appear:
Fix 6: Avoid State Initialization in Cells
Debugging Performance
Use Instruments to identify the bottleneck:
Common Pitfalls
- Using
AsyncImageinside lazy stacks:AsyncImagestarts a new download every time a cell appears during scrolling. It does not cache images between appearances. Use a dedicated image caching library (Kingfisher, SDWebImage, or a customNSCache-backed loader) for smooth scrolling. - Heavy
onAppearclosures: Code inonAppearruns on the main thread when the cell is created. Network requests, database queries, or complex computations inonAppearcause frame drops. Move heavy work to a background task with.task {}(async) or dispatch to a background queue. - Variable cell heights without explicit frames: When cells have dynamic heights,
LazyVStackmust measure each one by calling the body. This measurement cost adds up during fast scrolling. Use.frame(height:)for fixed-height cells or pre-calculate heights when possible. - Too many view modifiers per cell: Each modifier (
.shadow(),.clipShape(),.background(),.overlay()) adds a layer to the view hierarchy. Dozens of modifiers per cell multiply the rendering cost. Consolidate modifiers and avoid expensive effects like.blur()or.shadow()in scrolling cells. - Not using
idcorrectly inForEach: Without a stableid, SwiftUI may recreate views unnecessarily during scrolling. Use\.selfonly for simple value types. For model objects, conform toIdentifiablewith a stableidproperty so SwiftUI can reuse existing views.
Summary
- Stuttering is caused by expensive on-demand view creation during scrolling
- Simplify cell views, use fixed heights, and cache images to reduce per-cell cost
- Prefer
ListoverScrollView+LazyVStackfor large datasets (cell recycling) - Move heavy work out of
onAppearand into background tasks with.task {} - Profile with Instruments (Time Profiler) to identify which cells or modifiers are causing frame drops
Related reading
- Putting a simple if-then-else statement on one line
- PyPy -- How can it possibly beat CPython?
- Pyramids dynamic programming
- Python - How can I make this code asynchronous?
- R cannot be resolved - Android error
- R cannot be resolved - Android error
- Python - Is a dictionary slow to find frequency of each character?
- Python - Speed up an A Star Pathfinding Algorithm

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.