Skip to content

Roster view auto-loads large datasets on open, causing severe performance issues for companies with thousands of employees #4417

@binhtt6

Description

@binhtt6

Information about bug

Description

When opening the Roster view (/hr/roster), the system immediately starts loading and rendering employee shift data without requiring any user input or filters.

For organizations with a large number of employees (e.g. 2,000–10,000+), this results in:

Long initial load times (several seconds to tens of seconds)
UI freezing or becoming unresponsive
High server load due to large queries (Employee + Shift Assignment + related data)
Poor user experience, especially when users only intend to view a subset (e.g. a department or a few days)

The issue occurs before the user has a chance to apply any filters, making the feature difficult to use in real-world enterprise environments.

Module

HR

Version

Frappe HR version-16

Installation method

None

Relevant log output / Stack trace / Full Error Message.

Description

The current Roster view (/hr/roster) loads and renders the entire employee dataset at once, including all shift assignments within the selected date range.

This approach does not scale for organizations with a large workforce (e.g. thousands of employees). Rendering a full grid (employees × days) leads to:

Slow initial load times
UI freezing due to large DOM size
High memory usage in the browser
Heavy backend queries (Employee + Shift Assignment)

The lack of lazy loading or virtualization makes the feature difficult to use in real-world enterprise environments.

Steps to Reproduce
Have a dataset with 2,000+ employees
Ensure Shift Assignments exist across multiple days

Open:

/hr/roster
Observe:
All employees are loaded at once
Browser becomes slow or unresponsive
Significant delay before interaction is possible
Expected Behavior

Roster view should support incremental data loading and efficient rendering, such as:

Load only a small subset of employees initially (e.g. 20–50 rows)
Load additional employees when scrolling (infinite scroll)
Render only visible rows (virtualized list/grid)
Current Behavior
All employees are fetched and rendered at once
No pagination, lazy loading, or virtual scrolling
Rendering cost grows linearly with employee count × date range
Impact
Poor UX for medium/large companies
Browser performance degradation (especially on lower-end machines)
Increased server load due to large unfiltered queries
Forces implementers to build custom roster solutions
Proposed Solution
1. Implement Lazy Loading (Infinite Scroll)
Initial load: 20–50 employees
Fetch next batch when user scrolls
Backend API supports offset/limit

Example:

def get_roster(limit=50, offset=0, filters=None):
    # return paginated employee roster data
2. Add Row Virtualization (Frontend)
Render only visible rows in viewport
Use techniques similar to:
virtual list / windowing
Prevent DOM explosion for large datasets
3. Backend Pagination Support
Add limit and offset to roster API
Enforce max limits to prevent large queries
4. Combine with Filter-first Strategy
Require:
Company
Department or Branch
Date range (with max limit)
Prevent loading entire company by default
Suggested UX Flow
User opens Roster → sees empty state
User selects filters (Company, Department, Date range)
Clicks "Load Roster"
System loads first 20–50 employees
Scroll → load more incrementally
Additional Notes
This issue is especially critical in ERPNext v16 deployments with large datasets
Many real-world implementations require custom overrides to handle this
Adding lazy loading would significantly improve scalability without breaking existing functionality
Suggested Enhancement Type
Performance improvement
Scalability enhancement
UX improvement
Environment (example)
ERPNext Version: v16
Frappe Version: v16
Employees: ~3000+
Conclusion

Introducing lazy loading and row virtualization in the Roster view would dramatically improve performance and usability for large organizations, making the feature viable at scale.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions