diff --git a/src/NexusMods.EventSourcing.Abstractions/Serialization/ISerializer.cs b/src/NexusMods.EventSourcing.Abstractions/Serialization/ISerializer.cs
index 24226e37..aff60ebc 100644
--- a/src/NexusMods.EventSourcing.Abstractions/Serialization/ISerializer.cs
+++ b/src/NexusMods.EventSourcing.Abstractions/Serialization/ISerializer.cs
@@ -30,5 +30,5 @@ public interface IVariableSizeSerializer<T> : ISerializer
 /// </summary>
 public interface IGenericSerializer : ISerializer
 {
-    public bool TrySpecialze(Type baseType, Type[] argTypes, [NotNullWhen(true)] out ISerializer? serializer);
+    public bool TrySpecialze(Type baseType, Type[] argTypes, Func<Type, ISerializer> serializerFinder, [NotNullWhen(true)] out ISerializer? serializer);
 }
diff --git a/src/NexusMods.EventSourcing/NexusMods.EventSourcing.csproj b/src/NexusMods.EventSourcing/NexusMods.EventSourcing.csproj
index bedb8716..8b66b735 100644
--- a/src/NexusMods.EventSourcing/NexusMods.EventSourcing.csproj
+++ b/src/NexusMods.EventSourcing/NexusMods.EventSourcing.csproj
@@ -5,6 +5,7 @@
     <ItemGroup>
       <PackageReference Include="DynamicData" Version="8.3.27" />
       <PackageReference Include="MemoryPack" Version="1.10.0" />
+      <PackageReference Include="Reloaded.Memory" Version="9.3.2" />
       <PackageReference Include="System.Reactive" Version="6.0.0" />
       <PackageReference Include="TransparentValueObjects" PrivateAssets="all" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
     </ItemGroup>
diff --git a/src/NexusMods.EventSourcing/Serialization/ArraySerializer.cs b/src/NexusMods.EventSourcing/Serialization/ArraySerializer.cs
new file mode 100644
index 00000000..10d44ca6
--- /dev/null
+++ b/src/NexusMods.EventSourcing/Serialization/ArraySerializer.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Buffers;
+using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
+using NexusMods.EventSourcing.Abstractions.Serialization;
+using Reloaded.Memory.Extensions;
+
+namespace NexusMods.EventSourcing.Serialization;
+
+public class GenericArraySerializer : IGenericSerializer
+{
+    public bool CanSerialize(Type valueType)
+    {
+        return false;
+    }
+
+    public bool TryGetFixedSize(Type valueType, out int size)
+    {
+        size = 0;
+        return false;
+    }
+
+    public bool TrySpecialze(Type baseType, Type[] argTypes, Func<Type, ISerializer> serializerFinder, [NotNullWhen(true)] out ISerializer? serializer)
+    {
+        if (!baseType.IsArray)
+        {
+            serializer = null;
+            return false;
+        }
+
+        var itemType = baseType.GetElementType()!;
+        var itemSerializer = serializerFinder(itemType);
+
+        if (itemSerializer.TryGetFixedSize(itemType, out var itemSize))
+        {
+            var type = typeof(FixedItemSizeArraySerializer<,>).MakeGenericType(itemType, itemSerializer.GetType());
+            serializer = (ISerializer) Activator.CreateInstance(type, itemSerializer, itemSize)!;
+            return true;
+        }
+        else
+        {
+            var type = typeof(VariableItemSizeSerializer<,>).MakeGenericType(itemType, itemSerializer.GetType());
+            serializer = (ISerializer) Activator.CreateInstance(type, itemSerializer, itemSize)!;
+            return true;
+        }
+    }
+}
+
+
+public class FixedItemSizeArraySerializer<TItem, TItemSerializer>(TItemSerializer itemSerializer, int itemSize) : IVariableSizeSerializer<TItem[]>
+    where TItemSerializer : IFixedSizeSerializer<TItem>
+{
+    public bool CanSerialize(Type valueType)
+    {
+        if (!valueType.IsArray)
+        {
+            return false;
+        }
+
+        return itemSerializer.CanSerialize(valueType.GetElementType()!);
+    }
+
+    public bool TryGetFixedSize(Type valueType, out int size)
+    {
+        size = 0;
+        return false;
+    }
+
+    public void Serialize<TWriter>(TItem[] value, TWriter output) where TWriter : IBufferWriter<byte>
+    {
+        var totalSize = sizeof(ushort) + (itemSize * value.Length);
+        var span = output.GetSpan(totalSize);
+        BinaryPrimitives.WriteUInt32BigEndian(span, (ushort)value.Length);
+
+        foreach (var item in value)
+        {
+            itemSerializer.Serialize(item, span.SliceFast(itemSize, itemSize));
+        }
+        output.Advance(totalSize);
+    }
+
+    public int Deserialize(ReadOnlySpan<byte> from, out TItem[] value)
+    {
+        var size = BinaryPrimitives.ReadUInt16BigEndian(from);
+        var array = GC.AllocateUninitializedArray<TItem>(size);
+
+        from = from.SliceFast(sizeof(ushort));
+        for (var i = 0; i < size; i++)
+        {
+            array[i] = itemSerializer.Deserialize(from.SliceFast(i * itemSize, itemSize));
+        }
+
+        value = array;
+        return sizeof(ushort) + (itemSize * size);
+    }
+}
+
+
+public class VariableItemSizeSerializer<TItem, TItemSerializer>(TItemSerializer itemSerializer, int itemSize) : IVariableSizeSerializer<TItem[]>
+    where TItemSerializer : IVariableSizeSerializer<TItem>
+{
+    public bool CanSerialize(Type valueType)
+    {
+        if (!valueType.IsArray)
+        {
+            return false;
+        }
+
+        return itemSerializer.CanSerialize(valueType.GetElementType()!);
+    }
+
+    public bool TryGetFixedSize(Type valueType, out int size)
+    {
+        size = 0;
+        return false;
+    }
+
+    public void Serialize<TWriter>(TItem[] value, TWriter output) where TWriter : IBufferWriter<byte>
+    {
+        var totalSize = sizeof(ushort) + (itemSize * value.Length);
+        var span = output.GetSpan(totalSize);
+        BinaryPrimitives.WriteUInt32BigEndian(span, (ushort)value.Length);
+
+        foreach (var item in value)
+        {
+            itemSerializer.Serialize(item, output);
+        }
+        output.Advance(totalSize);
+    }
+
+    public int Deserialize(ReadOnlySpan<byte> from, out TItem[] value)
+    {
+        var size = BinaryPrimitives.ReadUInt16BigEndian(from);
+        var array = GC.AllocateUninitializedArray<TItem>(size);
+
+        from = from.SliceFast(sizeof(ushort));
+        var offset = sizeof(ushort);
+        for (var i = 0; i < size; i++)
+        {
+            offset += itemSerializer.Deserialize(from.SliceFast(offset), out var item);
+            array[i] = item;
+        }
+
+        value = array;
+        return offset;
+    }
+}
diff --git a/src/NexusMods.EventSourcing/Serialization/EntityIdSerializer.cs b/src/NexusMods.EventSourcing/Serialization/EntityIdSerializer.cs
index c5f93794..31babdd6 100644
--- a/src/NexusMods.EventSourcing/Serialization/EntityIdSerializer.cs
+++ b/src/NexusMods.EventSourcing/Serialization/EntityIdSerializer.cs
@@ -43,7 +43,7 @@ public bool TryGetFixedSize(Type valueType, out int size)
         return false;
     }
 
-    public bool TrySpecialze(Type baseType, Type[] argTypes, [NotNullWhen(true)] out ISerializer? serializer)
+    public bool TrySpecialze(Type baseType, Type[] argTypes, Func<Type, ISerializer> serializerFinder, [NotNullWhen(true)] out ISerializer? serializer)
     {
         if (baseType != typeof(EntityId<>) || argTypes.Length != 1)
         {
diff --git a/src/NexusMods.EventSourcing/Serialization/EventSerializer.cs b/src/NexusMods.EventSourcing/Serialization/EventSerializer.cs
index ed51a5ab..d28a1c2b 100644
--- a/src/NexusMods.EventSourcing/Serialization/EventSerializer.cs
+++ b/src/NexusMods.EventSourcing/Serialization/EventSerializer.cs
@@ -15,21 +15,19 @@ namespace NexusMods.EventSourcing.Serialization;
 
 using MemberDefinition = (ParameterInfo Ref, ParameterInfo Base, ParameterExpression Variable, ISerializer Serializer);
 
-public sealed class BinaryEventSerializer : IEventSerializer
+public sealed class BinaryEventSerializer : IEventSerializer, IVariableSizeSerializer<IEvent>
 {
     private readonly PooledMemoryBufferWriter _writer;
 
     private readonly Dictionary<Type, EventSerializerDelegate> _serializerDelegates = new();
     private readonly Dictionary<UInt128, EventDeserializerDelegate> _deserializerDelegates = new();
 
-    private static readonly GuidSerializer _guidSerializer = new();
-
     /// <summary>
     /// Write an event to the given writer, and return the
     /// </summary>
     internal delegate void EventSerializerDelegate(IEvent @event);
 
-    private delegate IEvent EventDeserializerDelegate(ReadOnlySpan<byte> data);
+    private delegate int EventDeserializerDelegate(ReadOnlySpan<byte> data, out IEvent @event);
 
     public BinaryEventSerializer(IEnumerable<ISerializer> diInjectedSerializers, IEnumerable<EventDefinition> eventDefinitions)
     {
@@ -58,7 +56,8 @@ public ReadOnlySpan<byte> Serialize(IEvent @event)
     public IEvent Deserialize(ReadOnlySpan<byte> data)
     {
         var id = BinaryPrimitives.ReadUInt128BigEndian(data);
-        return _deserializerDelegates[id](SliceFastStart(data, 16));
+        var used = _deserializerDelegates[id](SliceFastStart(data, 16), out var @event);
+        return @event;
     }
 
 
@@ -165,6 +164,9 @@ private EventSerializerDelegate BuildVariableSizeSerializer(EventDefinition even
     private EventDeserializerDelegate BuildVariableSizeDeserializer(EventDefinition definition, MemberDefinition[] allParams,
         List<MemberDefinition> fixedParams, int fixedSize, List<MemberDefinition> unfixedParams)
     {
+
+        var outParam = Expression.Parameter(typeof(IEvent).MakeByRefType(), "output");
+
         var spanParam = Expression.Parameter(typeof(ReadOnlySpan<byte>));
 
         var ctorExpressions = new List<Expression>();
@@ -204,16 +206,22 @@ private EventDeserializerDelegate BuildVariableSizeDeserializer(EventDefinition
         var ctorCall = Expression.New(definition.Type.GetConstructors().First(c => c.GetParameters().Length == ctorParams.Length),
             ctorParams);
 
-        var casted = Expression.Convert(ctorCall, typeof(IEvent));
+        var casted = Expression.Assign(outParam, Expression.Convert(ctorCall, typeof(IEvent)));
         blockExprs.Add(casted);
+        blockExprs.Add(offsetVariable);
 
         var outerBlock = Expression.Block(ctorParams.Append(offsetVariable), blockExprs);
-        var lambda = Expression.Lambda<EventDeserializerDelegate>(outerBlock, spanParam);
+        var lambda = Expression.Lambda<EventDeserializerDelegate>(outerBlock, [spanParam, outParam]);
         return lambda.Compile();
     }
 
     private ISerializer GetSerializer(ISerializer[] serializers, Type type)
     {
+        if (type == typeof(IEvent))
+        {
+            return this;
+        }
+
         var result = serializers.FirstOrDefault(s => s.CanSerialize(type));
         if (result != null)
         {
@@ -225,18 +233,28 @@ private ISerializer GetSerializer(ISerializer[] serializers, Type type)
             var genericMakers = serializers.OfType<IGenericSerializer>();
             foreach (var maker in genericMakers)
             {
-                if (maker.TrySpecialze(type.GetGenericTypeDefinition(), type.GetGenericArguments(), out var serializer))
+                if (maker.TrySpecialze(type.GetGenericTypeDefinition(),
+                        type.GetGenericArguments(), t => GetSerializer(serializers, t), out var serializer))
                 {
                     return serializer;
                 }
             }
         }
 
+        if (type.IsArray)
+        {
+            var arrayMaker = serializers.OfType<GenericArraySerializer>().First();
+            arrayMaker.TrySpecialze(type, [type.GetElementType()!], t => GetSerializer(serializers, t), out var serializer);
+            return serializer!;
+        }
+
         throw new Exception($"No serializer found for {type}");
     }
 
     private EventDeserializerDelegate BuildFixedSizeDeserializer(EventDefinition definitions, MemberDefinition[] allDefinitions, List<MemberDefinition> fixedParams, int fixedSize)
     {
+        var outParam = Expression.Parameter(typeof(IEvent).MakeByRefType());
+
         var spanParam = Expression.Parameter(typeof(ReadOnlySpan<byte>));
 
         var blockExprs = new List<Expression>();
@@ -256,11 +274,13 @@ private EventDeserializerDelegate BuildFixedSizeDeserializer(EventDefinition def
 
         var ctorCall = Expression.New(definitions.Type.GetConstructors().First(c => c.GetParameters().Length == allDefinitions.Length),
             allDefinitions.Select(d => d.Variable));
-        var casted = Expression.Convert(ctorCall, typeof(IEvent));
+        var casted = Expression.Assign(outParam, Expression.Convert(ctorCall, typeof(IEvent)));
         blockExprs.Add(casted);
 
+        blockExprs.Add(Expression.Constant(fixedSize));
+
         var outerBlock = Expression.Block(allDefinitions.Select(d => d.Variable), blockExprs);
-        var lambda = Expression.Lambda<EventDeserializerDelegate>(outerBlock, spanParam);
+        var lambda = Expression.Lambda<EventDeserializerDelegate>(outerBlock, [spanParam, outParam]);
         return lambda.Compile();
 
     }
@@ -406,4 +426,25 @@ private EventSerializerDelegate BuildFixedSizeSerializer(EventDefinition eventDe
     }
 
 
+    public bool CanSerialize(Type valueType)
+    {
+        return valueType == typeof(IEvent);
+    }
+
+    public bool TryGetFixedSize(Type valueType, out int size)
+    {
+        size = 0;
+        return false;
+    }
+
+    public void Serialize<TWriter>(IEvent value, TWriter output) where TWriter : IBufferWriter<byte>
+    {
+        _serializerDelegates[value.GetType()](value);
+    }
+
+    public int Deserialize(ReadOnlySpan<byte> from, out IEvent value)
+    {
+        var used = _deserializerDelegates[BinaryPrimitives.ReadUInt128BigEndian(from)](SliceFastStart(from, 16), out value);
+        return 16 + used;
+    }
 }
diff --git a/src/NexusMods.EventSourcing/Services.cs b/src/NexusMods.EventSourcing/Services.cs
index 2e7c8bba..053fb8bf 100644
--- a/src/NexusMods.EventSourcing/Services.cs
+++ b/src/NexusMods.EventSourcing/Services.cs
@@ -11,6 +11,7 @@ public static class Services
     public static IServiceCollection AddEventSourcing(this IServiceCollection services)
     {
         return services
+            .AddSingleton<ISerializer, GenericArraySerializer>()
             .AddSingleton<ISerializer, GenericEntityIdSerializer>()
             .AddSingleton<ISerializer, StringSerializer>()
             .AddSingleton<ISerializer, BoolSerializer>()