FastCloner 3.5.2

Prefix Reserved
dotnet add package FastCloner --version 3.5.2
                    
NuGet\Install-Package FastCloner -Version 3.5.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FastCloner" Version="3.5.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FastCloner" Version="3.5.2" />
                    
Directory.Packages.props
<PackageReference Include="FastCloner" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FastCloner --version 3.5.2
                    
#r "nuget: FastCloner, 3.5.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FastCloner@3.5.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FastCloner&version=3.5.2
                    
Install as a Cake Addin
#tool nuget:?package=FastCloner&version=3.5.2
                    
Install as a Cake Tool

<div align="center">

<img width="512" alt="FastCloner" src="https://github.com/user-attachments/assets/9b6b82a3-892a-4607-9c57-6580ca856a37" />

FastCloner

The fastest and most reliable .NET deep cloning library.

FastCloner FastCloner License:MIT

FastCloner is a zero-dependency deep cloning library for .NET, from <code>.NET 4.6</code> to <code>.NET 10+</code>. It combines source generation with optimized reflection fallback, so deep cloning just works.

</div>

✨ Features

  • The Fastest - Benchmarked to beat all other libraries with third-party independent benchmarks verifying the performance. 300x speed-up vs Newtonsoft.Json and 160x vs System.Text.Json
  • The Most Correct - Built for the cases clone libraries get wrong: polymorphism, circular/shared references, readonly and immutable members, deep graphs, delegates, events, collections... Backed by 800+ tests, with documented limitations
  • Hybrid AOT - Uses generated clone code wherever possible, with targeted fallback to the runtime engine only where safety or correctness requires it
  • Automatic type discovery - The generator follows usages of generic and abstract types and emits concrete clone paths automatically
  • Embeddable - No dependencies outside the standard library. Source generator and reflection parts can be installed independently
  • Precise control - Override clone behavior per type or member with Clone, Reference, Shallow, or Ignore, at compile time or runtime
  • Selective tracking - FastCloner avoids identity and cycle-tracking overhead by default, but enables it when graph shape or [FastClonerPreserveIdentity] requires it
  • Easy Integration - FastDeepClone() for AOT cloning, DeepClone() for reflection cloning. FastCloner respects standard .NET attributes like [NonSerialized], so you can adopt it without depending on library-specific annotations
  • Production Ready - Used by projects like Foundatio, Jobbr, TarkovSP, SnapX, and WinPaletter, with over 300K downloads on NuGet

Getting Started

Install the package via NuGet:

dotnet add package FastCloner # Reflection
dotnet add package FastCloner.SourceGenerator # AOT

Clone via Reflection

using FastCloner.Code;
var clone = FastCloner.FastCloner.DeepClone(new { Hello = "world", MyList = new List<int> { 1 } });

For convenience, add the following method to your project. We intentionally don't ship this extension to make switching from/to FastCloner easier:

[return: NotNullIfNotNull(nameof(obj))]
public static T? DeepClone<T>(this T? obj)
{
    return FastCloner.FastCloner.DeepClone(obj);
}

Clone via Source Generator

[FastClonerClonable]
public class GenericClass<T>
{
    public T Value { get; set; }
}

public class MyClass
{
    public string StrVal { get; set; }
}

// [FastClonerClonable] is only required on types where you call .FastDeepClone()
var original = new GenericClass<List<MyClass>> { Value = new List<MyClass> { new MyClass { StrVal = "hello world" } } };
var clone = original.FastDeepClone();

Advanced Usage

Customizing Clone Behavior

FastCloner supports behavior attributes that control how types and members are cloned:

Behavior Effect
Clone Deep recursive copy
Reference Return original instance unchanged
Shallow MemberwiseClone without recursion
Ignore Return default
Compile-time (Attributes)

Apply attributes to types or members. Member-level attributes override type-level:

[FastClonerReference]  // Type-level: all usages preserve reference
public class SharedService { }

public class MyClass
{
    public SharedService Svc { get; set; }      // Uses type-level → Reference
    
    [FastClonerBehavior(CloneBehavior.Clone)]   // Member-level override → Clone
    public SharedService ClonedSvc { get; set; }
    
    [FastClonerIgnore]                          // → null/default
    public CancellationToken Token { get; set; }
    
    [FastClonerShallow]                         // → Reference copied directly
    public ParentNode Parent { get; set; }
}

Shorthand attributes: [FastClonerIgnore], [FastClonerShallow], [FastClonerReference]
Explicit: [FastClonerBehavior(CloneBehavior.X)]

Runtime (Reflection only)

Configure type behavior dynamically. Runtime settings are checked before attributes:

FastCloner.FastCloner.SetTypeBehavior<MySingleton>(CloneBehavior.Reference);
FastCloner.FastCloner.ClearTypeBehavior<MySingleton>();    // Reset one
FastCloner.FastCloner.ClearAllTypeBehaviors();             // Reset all

Note: Changing runtime behavior invalidates the cache. Try to configure once at startup, or use compile-time attributes when possible.

Precedence (highest to lowest)
  1. Runtime SetTypeBehavior<T>()
  2. Member-level attribute
  3. Type-level attribute on member's type
  4. Default behavior

Cache Management

FastCloner.FastCloner.ClearCache();  // Free memory from reflection cache

Generic Classes and Abstract Types

The source generator automatically discovers which concrete types your generic classes and abstract hierarchies are used with:

Generic types - The generator scans your codebase for usages like MyClass<int> or MyClass<Customer> and generates specialized cloning code:

[FastClonerClonable]
public class Container<T>
{
    public T Value { get; set; }
}

// Source generator finds this usage and generates cloning code for Container<int>
var container = new Container<int> { Value = 42 };
var clone = container.FastDeepClone();

Abstract classes - The generator automatically finds all concrete derived types in your codebase:

[FastClonerClonable]
public abstract class Animal
{
    public string Name { get; set; }
}

public class Dog : Animal
{
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public bool IsIndoor { get; set; }
}

// Cloning via the abstract type works - the generator discovered Dog and Cat
Animal pet = new Dog { Name = "Buddy", Breed = "Labrador" };
Animal clone = pet.FastDeepClone(); // Returns a cloned Dog

Explicitly Including Types

When a type is only used dynamically (not visible at compile time), use [FastClonerInclude] to ensure the generator creates cloning code for it:

[FastClonerClonable]
[FastClonerInclude(typeof(Customer), typeof(Order))] // Include types used dynamically
public class Wrapper<T>
{
    public T Value { get; set; }
}

For abstract classes, you can also use [FastClonerInclude] to add derived types that aren't in your codebase (e.g., from external assemblies):

[FastClonerClonable]
[FastClonerInclude(typeof(ExternalPlugin))] // Add external derived types
public abstract class Plugin
{
    public string Name { get; set; }
}

Custom Cloning Context

For advanced scenarios, create a custom cloning context to explicitly register types you want to clone. This is useful when you need a centralized cloning entry point or want to clone types from external assemblies:

public class Customer
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string City { get; set; }
}

// Create a context and register types to clone
[FastClonerRegister(typeof(Customer), typeof(Address))]
public partial class MyCloningContext : FastClonerContext { }

Using the context:

MyCloningContext ctx = new MyCloningContext();

// Clone with compile-time type safety
Customer clone = ctx.Clone(original);

// Check if a type is handled by this context
bool handled = ctx.IsHandled(typeof(Customer)); // true

// Try to clone (returns false for unregistered types)
if (ctx.TryClone(obj, out var cloned))
{
    // Successfully cloned
}

Nullability Trust

The generator can be instructed to fully trust nullability annotations. When [FastClonerTrustNullability] attribute is applied, FastCloner will skip null checks for non-nullable reference types (e.g., string vs string?), assuming the contract is valid.

[FastClonerClonable]
[FastClonerTrustNullability] // Skip null checks for non-nullable members
public class HighPerformanceDto
{
    public string Id { get; set; } // No null check generated
    public string? Details { get; set; } // Null check still generated
}

This eliminates branching and improves performance slightly. If a non-nullable property is actually null at runtime, this may result in a NullReferenceException in the generated code.

Safe Handles

When you have a struct that acts as a handle to internal state or a singleton (where identity matters), use [FastClonerSafeHandle]. This tells FastCloner to shallow-copy the readonly fields instead of deep-cloning them, preserving the original internal references.

[FastClonerSafeHandle]
public struct MyHandle
{
    private readonly object _internalState; // Preserved (shared), not deep cloned
    public int Value; // Cloned normally
}

This is the default behavior for system types like System.Net.Http.Headers.HeaderDescriptor to prevent breaking internal framework logic. Use this attribute if your custom structs behave similarly.

Identity Preservation

By default, FastCloner prioritizes performance by not tracking object identity during cloning. This means if the same object instance appears multiple times in your graph, each reference becomes a separate clone.

For scenarios where you need to preserve object identity (e.g., shared references should remain shared in the clone), use [FastClonerPreserveIdentity]:

[FastClonerClonable]
[FastClonerPreserveIdentity] // Enable identity tracking for this type
public class Document
{
    public User Author { get; set; }
    public User LastEditor { get; set; } // May reference the same User as Author
}

var doc = new Document { Author = user, LastEditor = user };
var clone = doc.FastDeepClone();
// clone.Author == clone.LastEditor (same cloned instance)

The attribute can be applied at type level or member level:

[FastClonerClonable]
public class Container
{
    // Only this member tracks identity
    [FastClonerPreserveIdentity]
    public List<Node> Nodes { get; set; }
    
    // This member clones without identity tracking (faster)
    public List<Item> Items { get; set; }
}

You can also explicitly disable identity preservation for a member when the type has it enabled:

[FastClonerClonable]
[FastClonerPreserveIdentity]
public class Graph
{
    public Node Root { get; set; }
    
    [FastClonerPreserveIdentity(false)] // Opt out for this member
    public List<string> Labels { get; set; }
}

Note: Identity preservation adds overhead for tracking seen objects. Circular references are always detected regardless of this setting.

Limitations

  • Cloning unmanaged resources, such as IntPtrs may result in side-effects, as there is no metadata for the length of buffers such pointers often point to.
  • ReadOnly and Immutable collections are tested to behave well if they follow basic conventions.
  • With reflection, cloning deeply nested objects switches from recursion to iterative approach on the fly. The threshold for this can be configured by changing FastCloner.MaxRecursionDepth, iterative approach is marginally slower.

Performance

FastCloner is the fastest deep cloning library across both reflection-based and AOT workloads. It was benchmarked against every library capable of cloning objects I've been able to find:

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26220.7271)
Intel Core i7-8700 CPU 3.20GHz (Max: 3.19GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.100

| Method             | Mean        | Error      | StdDev     | Median      | Ratio  | RatioSD | Rank | Gen0   | Gen1   | Allocated | Alloc Ratio |
|------------------- |------------:|-----------:|-----------:|------------:|-------:|--------:|-----:|-------:|-------:|----------:|------------:|
| FastCloner         |    10.25 ns |   0.219 ns |   0.183 ns |    10.24 ns |   1.00 |    0.02 |    1 | 0.0115 |      - |      72 B |        1.00 |
| DeepCopier         |    23.37 ns |   0.448 ns |   0.582 ns |    23.29 ns |   2.28 |    0.07 |    2 | 0.0115 |      - |      72 B |        1.00 |
| DeepCopy           |    40.56 ns |   3.589 ns |  10.583 ns |    43.56 ns |   3.96 |    1.03 |    3 | 0.0115 |      - |      72 B |        1.00 |
| DeepCopyExpression |   126.05 ns |   3.355 ns |   9.892 ns |   129.32 ns |  12.30 |    0.98 |    4 | 0.0356 |      - |     224 B |        3.11 |
| AutoMapper         |   135.07 ns |   6.097 ns |  17.976 ns |   143.16 ns |  13.18 |    1.76 |    5 | 0.0114 |      - |      72 B |        1.00 |
| DeepCloner         |   261.42 ns |  14.113 ns |  41.614 ns |   282.99 ns |  25.51 |    4.06 |    6 | 0.0367 |      - |     232 B |        3.22 |
| ObjectCloner       |   336.89 ns |  14.249 ns |  42.012 ns |   355.28 ns |  32.87 |    4.12 |    7 | 0.0534 |      - |     336 B |        4.67 |
| MessagePack        |   499.71 ns |  20.831 ns |  61.420 ns |   524.63 ns |  48.75 |    6.02 |    8 | 0.0315 |      - |     200 B |        2.78 |
| ProtobufNet        |   898.60 ns |  34.925 ns | 102.978 ns |   934.13 ns |  87.67 |   10.11 |    9 | 0.0782 |      - |     496 B |        6.89 |
| NClone             |   904.75 ns |  33.559 ns |  98.949 ns |   919.05 ns |  88.27 |    9.73 |    9 | 0.1488 |      - |     936 B |       13.00 |
| SystemTextJson     | 1,687.39 ns |  70.341 ns | 201.821 ns | 1,766.14 ns | 164.63 |   19.79 |   10 | 0.1755 |      - |    1120 B |       15.56 |
| NewtonsoftJson     | 3,147.66 ns | 109.097 ns | 321.676 ns | 3,269.96 ns | 307.10 |   31.67 |   11 | 0.7286 | 0.0038 |    4592 B |       63.78 |
| FastDeepCloner     | 3,970.90 ns | 155.503 ns | 458.505 ns | 4,128.09 ns | 387.41 |   45.01 |   12 | 0.2060 |      - |    1304 B |       18.11 |
| AnyCloneBenchmark  | 5,102.40 ns | 239.089 ns | 704.959 ns | 5,370.93 ns | 497.81 |   68.98 |   13 | 0.9003 |      - |    5656 B |       78.56 |

You can run the benchmark locally to verify the results.

Build Times & IDE Performance

The source generator is designed to work with Roslyn's incremental model. It uses ForAttributeWithMetadataName, turns Roslyn symbols into stable TypeModel / MemberModel records early, and keeps ISymbol, syntax nodes, and Compilation out of the output pipeline.

  • Incremental pipeline - Type analysis happens during the transform step, so codegen re-runs only when decorated types or relevant usage data changes.
  • Stable models - TypeModel and MemberModel hold precomputed data instead of Roslyn symbols, which keeps incremental caching effective across edits.
  • No CompilationProvider in output - The output pipeline intentionally avoids it to reduce broad invalidation and unnecessary regeneration.
  • Deterministic collection equality - EquatableArray is used so generator model collections compare cleanly in the incremental pipeline.
  • Inlining of one-off helpers - Helpers used once are inlined to keep generated clone paths direct.

Internalization

For consumers who wish to embed FastCloner directly without adding a dependency, use the internalization builder project.

Example command:

dotnet run --project src/FastCloner.Internalization.Builder/FastCloner.Internalization.Builder.csproj -- \
  --root-namespace MyLibrary.FastCloner \
  --output ../MyLibrary/FastCloner \
  --preprocessor "MODERN=true;" \
  --fqn all \
  --visibility internal \
  --public-api none \
  --runtime-only true \
  --self-check

CLI options:

  • --root-namespace <ns>: Rewrites FastCloner namespaces to your target root namespace.
  • --preprocessor <SYMBOL=VALUE;...>: Per-symbol preprocessor transformation input.
    • VALUE=true|false is recognized as boolean and enables full condition resolution/removal where possible.
    • any other value is used as direct replacement in #if expressions (e.g., SOMETHING=random_text).
    • This lets the builder resolve #if branches ahead of time and emit target-specific code.
  • --fqn <prefix1|prefix2|...>: Fully qualifies matching external metadata types in generated code.
    • Use all to qualify all external metadata types.
    • Use prefixes such as System|System.Collections to limit qualification to selected namespaces.
    • This is useful when embedding FastCloner into a project that already defines colliding namespaces or type names.
  • --implicit-usings <ns1;ns2;...>: Namespaces the target project already imports implicitly.
    Generated global usings for these namespaces are omitted.
    Default is empty, so generated code carries explicit usings.
  • --visibility <public|internal>: Top-level visibility rewrite policy.
  • --public-api <none|fastcloner|extensions|behaviors|all>: Keeps selected public surface when --visibility internal is used.
  • --runtime-only <true|false>: Includes only runtime clone engine files.
  • --dry-run: Prints planned output files and transform stats without writing.
  • --self-check: Compiles generated source tree and reports compile errors.

Contributing

If you are looking to add new functionality, please open an issue first to verify your intent is aligned with the scope of the project. The library is covered by over 800 tests, please run them against your work before proposing changes. Tests run in parallel to verify thread-safety of the library (with targeted exceptions). Run dotnet test from the cloned repo root. We also run benchmark regression analysis on every pull request to next; if a change causes a measurable performance regression, the PR should clearly justify that trade-off. When reporting issues, providing a minimal reproduction we can plug in as a new test greatly reduces turnaround time. We use TUnit for testing.

Each PR gets an updated benchmark report comment from github-actions, so you can spot regressions early and iterate before merge.

<details> <summary>Example benchmark report</summary>

Status Benchmark Delta Time Delta Alloc
🟢 DynamicWithArray -15% faster ~same
DynamicWithDictionary +5% slower ~same
DynamicWithNestedObject ~same ~same
FileSpec -4% faster ~same
🟢 LargeEventDocument_10MB -7% faster ~same
LargeLogBatch_10MB ~same ~same
MediumNestedObject ~same ~same
ObjectDictionary_50 ~same ~same
ObjectList_100 -2% faster ~same
🟢 SmallObject -6% faster ~same
SmallObjectWithCollections -2% faster ~same
StringArray_1000 ~same ~same

</details>

<details> <summary>Tests Troubleshooting</summary>

Rider: automatic tests discovery

  • Temporarily disable VSTest adapters support (Build, Execution, Deployment > Unit Testing > VSTest)
  • Enable Testing Platform support (Build, Execution, Deployment > Unit Testing > Testing Platform)
  • Re-enable VSTest adapters support
  • Rebuild / refresh the test explorer

</details>

License

This library is licensed under the MIT license. 💜

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net46 is compatible.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.6

    • No dependencies.
  • .NETStandard 2.0

    • No dependencies.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on FastCloner:

Package Downloads
Jobbr.Server

Scaffolding that manages the Jobbr server and uses other compomenents depending on the registration

BXJG.Common

Package Description

SPTarkov.Server.Core

Core library for the Single Player Tarkov server.

FastCloner.Contrib

Extends FastCloner with support for certain special types.

Unleasharp.DB.Base

A multi-purpose database query building library. Generic abstractions.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.5.2 0 3/10/2026
3.5.1 301 3/6/2026
3.5.0 39 3/6/2026
3.4.7 2,792 2/26/2026
3.4.6 1,171 2/25/2026
3.4.5 2,467 2/23/2026
3.4.4 16,906 1/27/2026
3.4.3 6,953 1/19/2026
3.4.2 806 1/17/2026
3.4.1 129 1/16/2026
3.4.0 8,367 1/8/2026
3.3.23 2,999 1/5/2026
3.3.22 1,017 12/30/2025
3.3.21 117 12/30/2025
3.3.20 12,035 12/10/2025
3.3.19 2,696 12/5/2025
3.3.18 6,022 12/2/2025
3.3.17 14,183 11/15/2025
3.3.16 54,087 10/5/2025
3.3.15 649 10/2/2025
Loading failed