Performance Profiling
Starting with Neos 9.0.7, the Content Repository contains a performance profiler.
Starting with Neos 9.1, the Neos content repository contains a built-in performance profiler you can optionally enable. We use the profiler internally to debug performance-related issues, but it is also available for you to use.
The profiler is only meant for development usage, and NOT on a production system.
To enable the profiler, use the following Settings.yaml:
Neos:
  ContentRepositoryRegistry:
    presets:
      'default':
        # PERFORMANCE TRACING (Local Debugging)
        # To enable Performance Tracing, comment-in the following lines:
        performanceTracer:
          factoryObjectName: Neos\ContentRepository\Core\Infrastructure\Tracing\LogFileTracerFactory
          options:
            fileName: '%FLOW_PATH_DATA%Logs/ContentRepositoryProfile.log'
            # how long should a mark be at least, to be logged? if 0, everything is shown.
            minimumMarkDurationMs: 1Currently, mostly write operations (commands being executed) are profiled.
The profiles then look like this:
=== Trace started at 2025-10-23 15:31:54 ===
[1761233514.999921] > ContentRepository::handle {"c":"Neos\\ContentRepository\\Core\\Feature\\NodeMove\\Command\\MoveNodeAggregate"}
[1761233515.001142]     • AuthProvider::canExecuteCommand (+1.2 ms)   
[1761233515.014465]     • CommandBus::handle (+13.3 ms)   
[1761233515.024987]     • EventStore::commit (+10.5 ms)   
[1761233515.025036]   > SubscriptionEngine::catchUpSubscriptions
[1761233515.033295]       • Projection::apply (+7.6 ms)   {"subscription":"contentGraph","event":"NodeAggregateWasMoved"}
[1761233515.035002]       • Projection::apply (+1.7 ms)   {"subscription":"Neos.Neos:DocumentUriPathProjection","event":"NodeAggregateWasMoved"}
[1761233515.036070]       • Projection::apply (+1.1 ms)   {"subscription":"Neos.Neos:PendingChangesProjection","event":"NodeAggregateWasMoved"}
[1761233515.045640]   < SubscriptionEngine::catchUpSubscriptions (20.604 ms)
[1761233515.045649]     • SubscriptionEngine::catchUpActive (+9.6 ms)   
[1761233515.045677] < ContentRepository::handle (45.756 ms)#Interpreting Profile Results
In the profile above, you can directly see how long the different projection updates took; or if a CatchUpHook took too much time.
#Usage of Plumber for advanced profiling
You can also use Sandstorm.Plumber, starting with release 5.1.0, which auto-configures a hook and displays the Content Repository profiling in the timeline view.