Angular trackBy
Learn Angular trackBy with ngFor, performance optimization, DOM reuse, Signals integration, virtual scrolling, enterprise examples, best practices, and interview questions.
Rendering lists is one of the most common tasks in Angular applications.
Whether you're displaying:
- Customers
- Orders
- Products
- Transactions
- Employees
- Notifications
Angular must decide which DOM elements should be created, updated, reused, or removed whenever the list changes.
Without trackBy, Angular may recreate many DOM elements unnecessarily.
Using trackBy helps Angular identify list items efficiently, resulting in:
- Faster rendering
- Better scrolling performance
- Lower memory usage
- Improved user experience
Table of Contents
- What is trackBy?
- Why trackBy is Important
- How Angular Renders Lists
- Using trackBy
- How DOM Reuse Works
- Signals + trackBy
- Virtual Scrolling
- Enterprise Banking Example
- Performance Best Practices
- Common Mistakes
- Top 10 Interview Questions
- Summary
What is trackBy?
trackBy is a function used with *ngFor that tells Angular how to uniquely identify each item in a collection.
Instead of comparing entire objects,
Angular compares the unique identifier returned by trackBy.
Without trackBy
flowchart LR
OldList --> Angular
Angular --> RemoveDOM
Angular --> CreateDOM
CreateDOM --> UpdatedList
Every list update may recreate multiple DOM elements.
With trackBy
flowchart LR
OldList --> TrackBy
TrackBy --> ReuseDOM
ReuseDOM --> UpdatedList
Only changed items are updated.
Why trackBy Matters
Suppose a table contains:
- 10,000 customers
Only one customer's name changes.
Without trackBy,
Angular may recreate many DOM elements.
With trackBy,
Angular updates only the affected row.
Benefits
- Faster rendering
- Less DOM manipulation
- Better performance
- Smoother scrolling
Default List Rendering
<ul>
<li *ngFor="let user of users">
{{ user.name }}
</li>
</ul>
Angular identifies items by object identity.
If object references change,
Angular may recreate DOM nodes.
Using trackBy
<ul>
<li
*ngFor="let user of users;
trackBy: trackByUserId">
{{ user.name }}
</li>
</ul>
Component
trackByUserId(
index: number,
user: User
): number {
return user.id;
}
Angular now uses user.id to identify each row.
DOM Reuse Architecture
flowchart TD
OldDOM
OldDOM --> TrackBy
TrackBy --> ExistingRows
TrackBy --> NewRows
ExistingRows --> ReusedDOM
NewRows --> CreatedDOM
ReusedDOM --> UpdatedUI
CreatedDOM --> UpdatedUI
Example Without trackBy
users = [
{id:1,name:'Alice'},
{id:2,name:'Bob'},
{id:3,name:'Charlie'}
];
After fetching updated data
users = [
{id:1,name:'Alice'},
{id:2,name:'Robert'},
{id:3,name:'Charlie'}
];
Even though only one name changed,
Angular may recreate multiple DOM elements if object references are new.
Example With trackBy
trackByUserId(
index:number,
user:User
){
return user.id;
}
Angular recognizes:
- User 1 → Same
- User 2 → Update existing row
- User 3 → Same
Most DOM elements are reused.
Rendering Comparison
| Scenario | Without trackBy | With trackBy |
|---|---|---|
| DOM Recreation | High | Low |
| Rendering Speed | Slower | Faster |
| Memory Usage | Higher | Lower |
| Scrolling | Less Smooth | Smooth |
| Enterprise Apps | Not Recommended | Recommended |
trackBy with Signals
Signals work naturally with trackBy.
users = signal<User[]>([]);
Template
<li
*ngFor="let user of users();
trackBy: trackByUserId">
{{ user.name }}
</li>
Updating one Signal value
this.users.update(users =>
users.map(user =>
user.id === 2
? {...user,name:'Robert'}
: user
)
);
Only the affected DOM element is updated.
Signals + trackBy Architecture
flowchart LR
Signal
Signal --> UpdatedList
UpdatedList --> TrackBy
TrackBy --> DOMReuse
DOMReuse --> UI
trackBy with Virtual Scrolling
Large datasets should combine:
- Virtual Scrolling
- trackBy
<cdk-virtual-scroll-viewport
itemSize="50">
<div
*cdkVirtualFor="let customer of customers;
trackBy: trackByCustomerId">
{{ customer.name }}
</div>
</cdk-virtual-scroll-viewport>
Benefits
- Extremely low memory usage
- High rendering performance
- Smooth scrolling
Virtual Scrolling + trackBy
flowchart TD
LargeDataset
LargeDataset --> VirtualScroll
VirtualScroll --> TrackBy
TrackBy --> VisibleDOM
VisibleDOM --> UI
Enterprise Banking Example
Customer Dashboard
Displayed Data
- Accounts
- Credit Cards
- Loans
- Transactions
- Investments
Each table may contain thousands of rows.
Recommended Architecture
- Signals
- OnPush
- trackBy
- Virtual Scrolling
- Lazy Loading
flowchart TD
RESTAPI
RESTAPI --> Signal
Signal --> CustomerList
CustomerList --> TrackBy
TrackBy --> VirtualScroll
VirtualScroll --> Dashboard
Benefits
- Fast rendering
- Efficient DOM reuse
- Better scalability
- Lower memory consumption
Performance Comparison
| Dataset Size | Without trackBy | With trackBy |
|---|---|---|
| 100 Rows | Good | Excellent |
| 1,000 Rows | Moderate | Excellent |
| 10,000 Rows | Poor | Excellent |
| Frequent Updates | Slow | Fast |
| Memory Usage | Higher | Lower |
Best Practices
- Always use
trackByfor dynamic lists. - Use stable unique identifiers such as database IDs.
- Combine
trackBywith OnPush Change Detection. - Use immutable updates.
- Combine with Signals for reactive state.
- Use Virtual Scrolling for very large lists.
- Avoid expensive computations inside
trackBy. - Keep
trackByfunctions simple and deterministic.
Common Mistakes
Returning Index
❌ Wrong
trackBy(
index:number,
user:User
){
return index;
}
Indexes change when items are inserted, removed, or reordered.
Returning Random Values
❌ Wrong
trackBy(){
return Math.random();
}
Angular cannot reuse DOM elements because the identifier changes every time.
Using Non-Unique Values
❌ Wrong
return user.name;
Names might not be unique.
Prefer:
return user.id;
Heavy Logic Inside trackBy
Keep it lightweight.
trackByUserId(
index:number,
user:User
){
return user.id;
}
Forgetting trackBy on Frequently Updated Lists
Applications displaying real-time data should almost always use trackBy.
trackBy vs Default Rendering
| Feature | Default | trackBy |
|---|---|---|
| DOM Recreation | Higher | Lower |
| Rendering Speed | Moderate | Fast |
| Memory Usage | Higher | Lower |
| List Updates | Less Efficient | Efficient |
| Large Datasets | Limited | Excellent |
Advantages
| Advantage | Benefit |
|---|---|
| DOM Reuse | Less rendering work |
| Better Performance | Faster UI |
| Lower Memory Usage | Better scalability |
| Smooth Scrolling | Better UX |
| Enterprise Ready | Excellent for large applications |
| Signals Compatible | Fine-grained rendering |
Top 10 trackBy Interview Questions
1. What is trackBy in Angular?
Answer
trackBy is a function used with *ngFor that tells Angular how to uniquely identify list items so it can reuse existing DOM elements instead of recreating them.
2. Why should you use trackBy?
Answer
It reduces unnecessary DOM creation, improves rendering speed, lowers memory usage, and provides smoother scrolling for dynamic lists.
3. How does Angular render lists without trackBy?
Answer
Angular primarily relies on object identity. If object references change, Angular may recreate DOM elements even when the underlying data represents the same items.
4. What should a trackBy function return?
Answer
A stable, unique identifier such as a database ID or UUID.
Example:
trackByUserId(
index:number,
user:User
){
return user.id;
}
5. Why is returning the index a bad practice?
Answer
Indexes change when items are inserted, removed, or reordered, causing Angular to treat existing items as different and recreate DOM elements unnecessarily.
6. How does trackBy improve performance?
Answer
Angular reuses existing DOM elements and updates only the items whose identities have changed, reducing rendering work.
7. Does trackBy work with Signals?
Answer
Yes. Signals update reactive state, while trackBy ensures Angular efficiently reuses DOM elements when rendering Signal-based lists.
8. Can trackBy be used with Virtual Scrolling?
Answer
Yes. Combining trackBy with Virtual Scrolling provides excellent performance for very large datasets.
9. What are common trackBy mistakes?
Answer
- Returning array indexes
- Returning random values
- Returning non-unique properties
- Adding expensive logic inside the
trackByfunction
10. When should you use trackBy?
Answer
Use trackBy whenever rendering dynamic or frequently changing collections, especially in enterprise applications with medium or large datasets.
Interview Cheat Sheet
| Requirement | Recommended Solution |
|---|---|
| Dynamic Lists | trackBy |
| Unique Identifier | Database ID / UUID |
| Large Lists | Virtual Scrolling + trackBy |
| UI State | Signals |
| Change Detection | OnPush |
| Async Data | RxJS |
| DOM Reuse | trackBy |
| Immutable Updates | Recommended |
| Enterprise Apps | trackBy + Signals + OnPush |
| Large Tables | trackBy + Virtual Scroll |
Summary
trackBy is one of the simplest yet most effective Angular performance optimization techniques. By providing Angular with a stable, unique identifier for each list item, it minimizes unnecessary DOM recreation and significantly improves rendering performance. When combined with Signals, OnPush Change Detection, Virtual Scrolling, and immutable updates, trackBy becomes an essential tool for building fast, scalable enterprise Angular applications.
Key Takeaways
- ✔
trackByuniquely identifies list items. - ✔ It enables Angular to reuse existing DOM elements.
- ✔ Use stable unique identifiers such as IDs.
- ✔ Avoid returning indexes or random values.
- ✔ Combine
trackBywith Signals and OnPush. - ✔ Use Virtual Scrolling for very large datasets.
- ✔ Keep
trackByfunctions lightweight. - ✔ Apply immutable updates for predictable rendering.
- ✔
trackByis critical for enterprise-scale applications. - ✔ Understanding
trackByis a common Angular interview expectation.
Next Article
➡️ 94-Virtual-Scrolling-QA.md