Skip to content

[Due for payment 2026-03-04] Cache buildSearchQueryJSON to avoid redundant PEG parsing #82994

Description

@marcaaron

Proposal: Cache search query parsing to eliminate redundant computation

Background

Expensify's search functionality uses a PEG grammar parser (buildSearchQueryJSON) that converts query strings into structured objects used across the app — search results, navigation tabs, filter bars, and type menus. This is a pure function: same input always produces the same output. In SearchUIUtils.ts, search type menu items expose parsed data through JavaScript getter properties (get searchQueryJSON()) that re-execute the full parser on every property access. There are ~14 such objects, and their properties are accessed by multiple components (NavigationTabBar, SearchTypeMenu, SearchContextProvider) during each render cycle.

Problem

When a user interacts with search-related screens, each render cycle triggers the PEG parser dozens of times with identical query strings via getter property accesses, blocking the JS thread with redundant computation that produces results already computed milliseconds earlier.

Solution

Add a module-level Map cache inside buildSearchQueryJSON, keyed on the query string. Before parsing, check if the result exists in the cache — if so, return it immediately. After parsing, store the result. Cap at 50 entries with oldest-first eviction to bound memory. All callers treat the returned object as read-only, making the cache safe.

Expected Outcome

Flow: create expense fab → add amount → add merchant → create expense → navigate to reports

  • Reduce render time across all components from 7,027ms → 5,203ms (-26%)
  • ManualOpenCreateExpense span: 479ms → 288ms (-40%)

PR: #82931

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2Engineering

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions