Skip to main content

Preact DevTools

Preact DevTools is a browser extension that provides a dedicated panel for inspecting, debugging, and profiling Preact applications. It allows you to examine component hierarchies, inspect props and state, track component updates, and measure performance.

Installation

Browser Extensions

Install the Preact DevTools extension for your browser:

Enabling DevTools Support

Preact automatically connects to DevTools when the extension is installed. To ensure compatibility, import the devtools connector:
import 'preact/devtools';
import { render } from 'preact';
import App from './App';

render(<App />, document.getElementById('app'));
The preact/debug package automatically imports preact/devtools, so if you’re using debug mode, you don’t need to import devtools separately.
Source: debug/src/index.js:2

How It Works

The devtools integration works by attaching to Preact’s options hooks:
// Simplified version of devtools/src/devtools.js
export function initDevTools() {
  const globalVar = typeof globalThis !== 'undefined'
    ? globalThis
    : typeof window !== 'undefined'
      ? window
      : undefined;

  if (globalVar && globalVar.__PREACT_DEVTOOLS__) {
    globalVar.__PREACT_DEVTOOLS__.attachPreact('11.0.0-beta.1', options, {
      Fragment,
      Component
    });
  }
}
Source: devtools/src/devtools.js:3-21 The extension injects a __PREACT_DEVTOOLS__ object into the global scope, which the devtools connector uses to establish communication between your app and the DevTools panel.

Features

Component Tree Inspection

The DevTools panel shows your component hierarchy in a tree structure:
  • View all rendered components
  • See component relationships (parent/child)
  • Identify component types (function vs class)
  • Inspect Fragment boundaries
  • Highlight components on hover

Props and State Inspection

Select any component to view its current state:
function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('Counter');
  
  return (
    <div>
      <h2>{name}</h2>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
In DevTools, you’ll see:
  • Props: Empty (no props passed)
  • State: { 0: 0, 1: "Counter" } (hooks are numbered)
  • Hooks: List of all hooks used

Live Editing

Modify component state directly in DevTools:
  1. Select a component
  2. Click on a state value
  3. Edit the value
  4. Press Enter to apply
The component will re-render with the new state immediately.

Component Highlighting

When you hover over a component in DevTools, it gets highlighted in the page with a colored overlay showing:
  • Component boundaries
  • Component name
  • Dimensions

Source Code Location

DevTools can show where components are defined in your source code. This requires the Babel JSX source plugin:
npm install --save-dev @babel/plugin-transform-react-jsx-source
// .babelrc
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx-source"]
  ]
}
With this enabled, you can click a component in DevTools to jump directly to its source code.

Profiling

The Profiler tab helps identify performance bottlenecks:
  1. Click “Start Profiling”
  2. Interact with your app
  3. Click “Stop Profiling”
  4. Analyze the results
The profiler shows:
  • Component render times
  • Number of renders
  • Why components re-rendered
  • Flame graphs of render cycles

Custom Hook Names

By default, hooks appear as numbered entries in DevTools. You can provide custom labels using addHookName:
import { addHookName } from 'preact/devtools';

function useCustomHook(initialValue) {
  const [value, setValue] = useState(initialValue);
  
  // Label this hook in DevTools
  addHookName(value, 'CustomValue');
  
  return [value, setValue];
}

function MyComponent() {
  const [count, setCount] = useCustomHook(0);
  
  return <div>{count}</div>;
}
Source: devtools/src/index.js:10-15 Now in DevTools, instead of seeing State: 0, you’ll see CustomValue: 0.

useDebugValue Alternative

Preact also supports React’s useDebugValue hook:
import { useDebugValue, useState } from 'preact/hooks';

function useCustomHook(initialValue) {
  const [value, setValue] = useState(initialValue);
  
  // Show in DevTools
  useDebugValue(value > 10 ? 'High' : 'Low');
  
  return [value, setValue];
}

Debugging Class Components

For class components, DevTools shows:
class Counter extends Component {
  state = { count: 0 };
  
  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };
  
  render() {
    return (
      <div>
        <p>{this.state.count}</p>
        <button onClick={this.increment}>+</button>
      </div>
    );
  }
}
DevTools displays:
  • Props: Component props
  • State: { count: 0 }
  • Context: Any context values consumed
  • Rendered by: Parent component

Debugging Context

When components use Context, DevTools shows the consumed values:
import { createContext } from 'preact';
import { useContext } from 'preact/hooks';

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  
  return <button className={theme}>Click me</button>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}
In DevTools, ThemedButton will show:
  • Hooks: Context: "dark"

Performance Profiling Tips

Identifying Expensive Renders

  1. Open the Profiler tab
  2. Start recording
  3. Perform actions in your app
  4. Stop recording
  5. Look for components with long render times (shown in red/yellow)

Understanding Why Components Rendered

The profiler shows why each component re-rendered:
  • Props changed: Component received new props
  • State changed: Component state was updated
  • Parent rendered: Parent component re-rendered
  • Context changed: Consumed context value changed
  • Hooks changed: Hook dependencies changed

Flame Graph Analysis

The flame graph visualizes render hierarchy:
  • Width represents render duration
  • Depth shows component nesting
  • Color indicates render time (green = fast, red = slow)

Browser Console Integration

With DevTools installed, Preact exposes additional debugging helpers:

$r - Selected Component

The currently selected component in DevTools is available as $r in the console:
// In console
$r.props    // View props
$r.state    // View state (class components)
$r._vnode   // Access internal vnode

Component Instance Access

For class components, $r is the component instance, so you can call methods:
// In console
$r.setState({ count: 100 })  // Modify state
$r.forceUpdate()             // Force re-render

Troubleshooting

DevTools Not Appearing

If the Preact panel doesn’t appear:
  1. Verify installation: Check that the extension is installed and enabled
  2. Check imports: Ensure you import preact/devtools or preact/debug
  3. Restart browser: Sometimes extensions need a restart
  4. Check console: Look for errors in the browser console
  5. Verify Preact: Make sure you’re actually using Preact, not React

DevTools Shows Empty Tree

If no components appear:
  1. Ensure your app has rendered components
  2. Check that render was called: render(<App />, container)
  3. Verify devtools is imported before rendering
  4. Check for JavaScript errors preventing render

Performance Issues

DevTools adds overhead. If your app is slow with DevTools:
  1. Close the DevTools panel when not needed
  2. Disable profiling when not actively profiling
  3. Use production builds for performance testing
  4. Close other browser extensions

Production Builds

DevTools should not be included in production builds. Most bundlers will automatically exclude it, but verify your production bundle doesn’t include devtools code.

Conditional Import

if (process.env.NODE_ENV !== 'production') {
  require('preact/devtools');
}

Build Configuration

Configure your bundler to exclude devtools in production:
// webpack.config.js
module.exports = {
  resolve: {
    alias: {
      'preact/devtools': process.env.NODE_ENV === 'production'
        ? 'empty-module'
        : 'preact/devtools'
    }
  }
};

Standalone DevTools

For environments without browser extensions (like React Native or Electron), you can use the standalone DevTools:
npm install --save-dev preact-devtools-standalone
import { initDevTools } from 'preact-devtools-standalone';

initDevTools();
This opens DevTools in a separate window.

Comparison with React DevTools

Preact DevTools is similar to React DevTools but:
  • Lighter weight: Smaller extension footprint
  • Preact-specific: Optimized for Preact’s architecture
  • Hook numbering: Hooks are numbered by default (use addHookName for labels)
  • Compatible: Can debug most Preact apps including those using preact/compat

Advanced: DevTools API

The DevTools connector exposes an API for advanced integrations:
if (window.__PREACT_DEVTOOLS__) {
  const api = window.__PREACT_DEVTOOLS__;
  
  // API is available for custom integrations
  // (Internal API, subject to change)
}
Source: devtools/src/devtools.js:11-20
The DevTools API is internal and may change between versions. Use at your own risk.

Build docs developers (and LLMs) love