Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/reatom/reatom/llms.txt

Use this file to discover all available pages before exploring further.

Reatom provides comprehensive developer tools for debugging and inspecting your application state, actions, and dependencies. This guide covers the built-in logger and the DevTools UI.

Quick Start

Install DevTools

npm install @reatom/devtools

Basic Logger Setup

The simplest way to debug Reatom apps is using the built-in connectLogger:
import { connectLogger } from '@reatom/core'

// Enable in development only
if (import.meta.env.DEV) {
  connectLogger()
}
This logs all state changes, action calls, and dependencies to your browser console.
Add this early in your application entry point, before any atoms are created or accessed.

Using the Logger

Basic Logging

import { atom, action, connectLogger } from '@reatom/core'

// Setup logger
connectLogger()

const counter = atom(0, 'counter')
const increment = action(() => {
  counter.set((v) => v + 1)
}, 'increment')

increment()
// Console output:
// [Reatom] increment
//   counter: 0 → 1

Filtering Logs

Filter which atoms and actions appear in logs:
import { connectLogger } from '@reatom/core'

connectLogger({
  // Only log atoms matching this pattern
  match: /^user|^auth/,
})

Excluding Private State

By convention, atoms starting with _ are private:
connectLogger({
  // Skip atoms/actions starting with underscore
  match: /^(?!_)/,
})
The default filter pattern in DevTools excludes names starting with _ or ._ to hide internal implementation details.

Log Levels and Formatting

import { connectLogger, log } from '@reatom/core'

// Setup logger first
connectLogger()

// Use LOG action for custom debugging
declare global {
  var LOG: typeof log
}
globalThis.LOG = log

// Now use anywhere in your code
const fetchUser = action(async (id: string) => {
  LOG('Fetching user:', id)
  const response = await wrap(fetch(`/api/users/${id}`))
  const user = await response.json()
  LOG('User loaded:', user)
  return user
}, 'fetchUser')
The logger automatically traces the call stack and shows which action triggered the log.

State Change Logging

Log only when specific state changes:
import { LOG } from './logger'

const Component = reatomComponent(() => {
  const data = useSomeData()
  
  // Logs only when data reference changes
  const currentData = LOG.state('componentData', data)
  
  return <div>{currentData}</div>
})

DevTools UI

The @reatom/devtools package provides a visual interface for inspecting your Reatom state graph.

Installation and Setup

1

Install the package

npm install @reatom/devtools
2

Create and mount DevTools

import { createDevtools } from '@reatom/devtools'

if (import.meta.env.DEV) {
  const devtools = createDevtools({
    initVisibility: true,
    initSize: 1000,
  })
  
  // Access globally
  globalThis.REATOM_DEVTOOLS = devtools
}
3

Access the UI

The DevTools UI automatically appears in the bottom-right corner of your browser window (in development mode).

DevTools Configuration

import { createDevtools } from '@reatom/devtools'

const devtools = createDevtools({
  // Show DevTools panel on load
  initVisibility: true, // default: true
  
  // Maximum number of log entries to keep
  initSize: 1000, // default: 1000
  
  // Custom color coding for different atoms
  getColor: (frame) => {
    if (frame.atom.name.startsWith('user')) return '#4CAF50'
    if (frame.atom.name.startsWith('api')) return '#2196F3'
    return '#9E9E9E'
  },
  
  // Custom name separator for hierarchical view
  separator: /\./, // default: /\.|
  
  // Prefix for private atoms to hide
  privatePrefix: '_', // default: '_'
})

DevTools API

The DevTools instance provides programmatic control:
// Show/hide the panel
devtools.show()
devtools.hide()

// Log custom messages
devtools.log('Custom event', { foo: 'bar' })

// Create inspectable state
const inspectableValue = devtools.state('myValue', initialState)

// Update from DevTools UI triggers this subscription
inspectableValue.subscribe((newValue) => {
  console.log('Value edited in DevTools:', newValue)
})

DevTools Features

Logs View

The main logs panel shows:
  • Action calls with parameters
  • State changes with before/after values
  • Dependency chains showing what triggered what
  • Timestamps for performance analysis
  • Stack traces for debugging

Filter Actions

Create custom filters to focus on specific parts of your state:
  • Filter mode: Show only matching logs
  • Hide mode: Hide matching logs
  • Exclude mode: Remove from collection entirely (performance optimization)
  • Highlight mode: Color-code matching logs
Filters support both regex patterns and value search (searches stringified payloads).
Save frequently-used filters to quickly switch between different debugging contexts.

Log Controls

  • Clear logs: Remove all collected logs
  • Clear lines: Remove cause chain highlight lines
  • Recording: Pause/resume log collection
  • Preview: Toggle inline payload preview
  • Time: Toggle timestamp display
  • Snap: Create snapshot of current visible logs
  • Size: Adjust log collection limit

States View

Hierarchical tree view of all atoms in your application:
  • Organized by name separator (e.g., user.profile.name)
  • Excludes actions and private atoms by default
  • Real-time updates via proto.updateHooks
  • “Reload” button to force snapshot refresh
  • “Log” button to output state to console
The states view uses structuredClone when possible, falling back to live data references for non-cloneable objects.

Inspector

Click any state value to open the inspector panel:

Inspector Actions

  • Edit: Open JSON form to modify state (uses JSON.parse)
  • History: View diff between current and previous states (max 10 entries)
  • Log to console: Output current value to browser console
  • Copy JSON: Copy stringified value to clipboard
  • Download: Save value as JSON file
  • Convert to plain JSON: Remove Reatom atoms from data structure
State edits from the inspector go through a special update action. They will trigger all normal subscribers and effects.

Cause Chain Tracing

Click any log entry to highlight its cause chain:
  • Visual lines connect causes to effects
  • Shows dependencies that triggered updates
  • Helps understand why state changed
  • Traces through async boundaries
// Example cause chain:
const searchQuery = atom('', 'searchQuery')
const debouncedQuery = computed(/* debounce logic */, 'debouncedQuery')
const searchResults = computed(async () => {
  const query = debouncedQuery()
  return await fetchResults(query)
}, 'searchResults').extend(withAsyncData())

// Clicking searchResults in DevTools shows:
// searchQuery → debouncedQuery → searchResults.pending → searchResults.data

Time Travel Debugging

Use snapshots to capture and restore state:
// Create snapshot
const snapshot = devtools.snap()

// Later: review historical state
// (Manual implementation - DevTools provides UI)

Integration with Browser DevTools

Chrome/Edge DevTools Extension

Reatom integrates with browser DevTools through the @reatom/devtools package:
  1. The DevTools UI renders in a Shadow DOM container with isolated styles
  2. Uses ObservableHQ Inspector for rich data visualization
  3. Includes jsondiffpatch for visual state diffs

Console Integration

import { connectLogger, log } from '@reatom/core'

// Setup
connectLogger()
globalThis.LOG = log

// Now all Reatom updates appear in console
const counter = atom(0, 'counter')
counter.set(5)
// Console: [Reatom] counter: 0 → 5

// Custom logs with stack traces
LOG('Debug checkpoint', { value: counter() })
// Console: [Reatom] LOG
//   "Debug checkpoint" { value: 5 }
//   (shows call stack)

Persistence

DevTools settings are saved to localStorage:
  • Filter configurations (with version key)
  • View preferences (logs vs. states)
  • Panel visibility
  • Size settings
Settings use Zod for validation to handle version migrations safely.

Performance Considerations

Production Builds

Always guard DevTools and logging with environment checks:
if (import.meta.env.DEV) {
  const { createDevtools } = await import('@reatom/devtools')
  const { connectLogger } = await import('@reatom/core')
  
  createDevtools()
  connectLogger()
}
This ensures DevTools code is tree-shaken from production bundles.

Log Collection Limits

Use the initSize option to prevent memory issues:
createDevtools({
  initSize: 500, // Fewer logs for memory-constrained environments
})
The DevTools automatically trim old logs when the limit is reached.

Exclude Filters

Use “exclude” mode filters for high-frequency atoms:
// Prevent logging high-frequency updates
devtools.addFilter({
  pattern: /_internal|scroll/,
  mode: 'exclude', // Drops logs before insertion
})

Debugging Recipes

Find Why State Changed

1

Open DevTools and find the atom

Look in the Logs view for the unexpected state change.
2

Click the log entry

This highlights the cause chain showing all dependencies that triggered the update.
3

Follow the chain backwards

Trace from effect back to cause to find the root trigger.

Debug Async Operations

Enable stack traces to see async call chains:
import { getStackTrace } from '@reatom/core'

const fetchData = action(async () => {
  LOG('Stack trace:', getStackTrace())
  const data = await wrap(fetch('/api/data'))
  LOG('Data loaded')
  return data
}, 'fetchData')
The logger shows the complete async execution path.

Inspect Complex State

Use the inspector’s “Convert to plain JSON” feature to remove Reatom wrappers:
  1. Click the state value in DevTools
  2. Click “Convert to plain JSON”
  3. Copy or download the plain object

Track State Over Time

Use history diffs to see how state evolved:
  1. Click a state value in the inspector
  2. Click “History” button
  3. Review visual diffs showing changes over time
History tracking uses reference equality. In-place mutations won’t appear in diffs - always create new objects/arrays.

Best Practices

  1. Name everything - Give all atoms and actions descriptive names for better logs
  2. Use namespacing - Structure names like user.profile.email for hierarchical views
  3. Filter aggressively - Hide internal implementation details with filters
  4. Check logs regularly - Catch unexpected updates early in development
  5. Use LOG liberally - Add logging to complex operations while developing
  6. Guard production - Always wrap DevTools in environment checks

Troubleshooting

DevTools Not Appearing

Check that:
  • DevTools is created before atoms are accessed
  • initVisibility is true
  • You’re in development mode
  • No console errors from DevTools initialization

Missing Logs

Ensure:
  • connectLogger() is called before atom updates
  • Your filters aren’t hiding the logs
  • Recording is enabled (check the “recording” toggle)

Performance Issues

If DevTools slows your app:
  • Reduce initSize limit
  • Add exclude filters for high-frequency atoms
  • Disable recording when not actively debugging
  • Close the DevTools panel (it still collects but renders less)

Further Reading