Now available on VS Code Marketplace & Open VSX (Cursor)

Surface
React performance patterns
worth reviewing.

Not every re-render is a problem. RenderGuard highlights patterns that can cause performance issues — you decide what's worth optimizing. 9 detectors, inline hints, and quick fixes, right in your editor.

UserList.tsx
const UserList = ({ users }) => {
  const sorted = users.sort((a, b) => a.name.localeCompare(b.name));
           ⚠ Unmemoized sort — consider useMemo for large datasets

  return (
    <div>
      {sorted.map((user, index) => (
                      ⚠ Array index as key
        <UserCard
          key={index}
          onClick={() => selectUser(user.id)}
                   ⚠ Inline function — matters if UserCard uses React.memo
        />
      ))}
    </div>
  );
};

Not every re-render is a problem. But some are.

React is designed to re-render. Most re-renders are cheap. The hard part is knowing which ones actually matter.

Render vs. commit

React can call your component, diff the output, and skip the DOM commit entirely. A re-render doesn't always mean a costly update. The key is knowing when it does.

🔍

Optimization has a cost

useMemo and useCallback aren't free. For cheap operations, the memoization overhead can exceed the cost of just re-computing. RenderGuard helps you find the patterns worth optimizing.

🔧

Hard to spot what matters

Performance patterns look like normal code. They're invisible in review because they're syntactically correct. You need static analysis to surface them for consideration.

Signals, not mandates

RenderGuard surfaces patterns for review. You decide what to act on.

⚠️

Inline Hints

Subtle annotations on detected patterns. Hover for context on when it matters and when you can safely ignore it.

📈

Pattern Density Scores

See which components have the most patterns worth reviewing — so you know where to focus when optimizing.

Quick Fixes

One-click useMemo/useCallback wrapping when you decide a pattern is worth optimizing. You choose, one at a time.

🌳

Component Tree Sidebar

Activity bar panel showing all components in the file, grouped by pattern density, with expandable details.

⚙️

Fully Configurable

Disagree with a detector? Disable it. Want gentle nudges? Set severity to "hint". Tailor it to your team's philosophy.

🚀

Fast

Static AST analysis via Babel — no type-checking overhead, no compilation step. Debounced on every keystroke.

Surfaces what code review misses

Each detection is a signal, not a mandate. Two tiers of analysis — from per-statement checks to data flow across components.

Tier 1 — Per-Statement Analysis

Inline Objects & Arrays

// Flagged: new ref — matters if Child uses React.memo
<Child style={{ color: 'red' }} />

// Safe
const style = useMemo(() => ({ color: 'red' }), []);
<Child style={style} />

Inline Functions

// Flagged: new ref — often fine for leaf components
<Button onClick={() => handleClick(id)} />

// Safe
const onClick = useCallback(() => handleClick(id), [id]);
<Button onClick={onClick} />

Missing React.memo

// Flagged: consider memo for expensive components
const UserCard = (props) => {
  return <span>{props.name}</span>;
};

// Safe
const UserCard = React.memo((props) => {
  return <span>{props.name}</span>;
});

Array Index as Key

// Flagged: causes remounts on reorder
items.map((item, i) => <Item key={i} />)

// Safe
items.map((item) => <Item key={item.id} />)

Unstable Hook Dependencies

// Flagged: missing deps defeats memoization
const val = useMemo(() => compute(a, b));

// Safe
const val = useMemo(() => compute(a, b), [a, b]);

Broad Context Consumption

// Flagged: subscribes to ALL changes
const ctx = useContext(AppContext);

// Safe: pick only what's needed
const { theme } = useContext(AppContext);
Tier 2 — Data Flow Analysis

Unmemoized Derived State

// Flagged: costly with large datasets
const filtered = items.filter(i => i.active);

// Safe
const filtered = useMemo(
  () => items.filter(i => i.active), [items]
);

Props Drilling

// Flagged: passes through without use
const Layout = ({ theme }) =>
  <Sidebar theme={theme} />;

// Not flagged: used in own logic
const Layout = ({ theme }) =>
  <div className={theme}></div>;

State Lifted Too High

// Flagged: state only used by one child
const Parent = () => {
  const [count, setCount] = useState(0);
  return <Counter count={count}
    setCount={setCount} />;
};

Install in seconds

Works with VS Code and Cursor. Zero configuration needed.

From Marketplace

One click install — search "RenderGuard" in the extensions panel or use the buttons below.

Install for VS Code Install for Cursor (Open VSX)

From Source

Clone the repo and run in development mode with F5.

$ git clone https://github.com/renderguard-dev/renderguard.git
$ cd renderguard/extension
$ npm install
$ npm run build

Get in touch

Have a question, feature request, or found a bug? We'd love to hear from you.

Or email us directly at hello@renderguard.dev