diff --git a/documentation/Built-in-Propeties.md b/documentation/Built-in-Properties.md
similarity index 100%
rename from documentation/Built-in-Propeties.md
rename to documentation/Built-in-Properties.md
diff --git a/documentation/NETFramework-NGEN.md b/documentation/NETFramework-NGEN.md
new file mode 100644
index 00000000000..c7ec1412d8d
--- /dev/null
+++ b/documentation/NETFramework-NGEN.md
@@ -0,0 +1,119 @@
+# .NET Framework NGEN Considerations
+
+NGEN is the name of the legacy native AOT technology used in .NET Framework. Compared to its modern .NET counter-part,
+NGEN has the following key characteristics:
+- Native code is always stored in separate images located in a machine-wide cache.
+- Native images are generated on user machines, typically during app installation, by an elevated process.
+- Native images are specific for a given IL image (its identity, *not* its location) and its exact dependencies as they are bound to at run-time.
+
+Check the [Ngen.exe (Native Image Generator)](https://learn.microsoft.com/en-us/dotnet/framework/tools/ngen-exe-native-image-generator) Microsoft Learn article for an overview of how NGEN works.
+
+## NGEN in Visual Studio
+
+Visual Studio use NGEN for almost everything that ships in the box. The sheer amount of code which needs to be
+compiled makes it impractical for native image generation to occur synchronously during installation. Instead,
+VS installer queues up assemblies for deferred compilation by the NGEN service, which typically happens when the
+machine is idle. To force native images to be generated, one can execute the following command in an elevated
+terminal window:
+
+```
+C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ngen eqi
+```
+
+The .NET Framework build of MSBuild is inserted into VS and it registers itself for NGEN by including `vs.file.ngenApplications`
+in the relevant [files.swr](https://github.com/dotnet/msbuild/blob/main/src/Package/MSBuild.VSSetup/files.swr) entries. MSBuild
+is hosted in several processes, most notably the stand-alone command line tool `MSBuild.exe` and the main IDE process `devenv.exe`.
+Because each process runs with slightly different dependencies - `MSBuild.exe` loads most of them from `[VS install dir]\MSBuild\Current\Bin`
+or `[VS install dir]\MSBuild\Current\Bin\[arch]` while `devenv.exe` has its own set loaded from other parts of the VS installation -
+we NGEN our code twice. This is encoded by multiple `vs.file.ngenApplications` entries for a single file in `files.swr`.
+The special `[installDir]\Common7\IDE\vsn.exe` entry represents devenv.
+
+The bad thing about this is that the system is fragile and adding a dependency often results in having to tweak `files.swr` or
+`devenv.exe.config`, the latter of which is generated from the file named `devenv.urt.config.tt` in the VS source tree. The good
+thing is that regressions, be it a failure to compile an NGEN image or a failure to use an NGEN image, are reliably detected
+by the VS PR gates so they are fixed before MSBuild is inserted into the product.
+
+## NGEN image loading rules
+
+The Common Language Runtime can be finicky about allowing a native image to load. We usually speak of "NGEN rejections" where a native
+image has successfully been created but it cannot be used at run-time. When it happens, the CLR falls back to loading the IL assembly
+and JITting code on demand, leading to sub-optimal performance.
+
+One major reason why a native image is rejected is loading into the LoadFrom context. The rules are excruciatingly complex, but suffice
+it to say that when an assembly is loaded by `Assembly.LoadFrom`, it is automatically disqualified from having its native image used.
+This is bad news for any app with an add-in system where extension assemblies are loaded by path.
+
+## SDK resolvers
+
+One class of assemblies loaded by MSBuild by path are SDK resolvers. MSBuild scans the `SdkResolvers` subdirectory to discover
+the set of resolvers to use when evaluating projects. Extensible in theory, though in reality only a couple of resolvers actually
+exist. Because resolvers ship as part of VS, it is not difficult to make sure their assemblies are properly NGENed. The hard part is
+loading them with the regular `Assembly.Load` so the native images can be used. MSBuild cannot simply extend its probing path to
+include the relevant subdirectories of `SdkResolvers` because 1) It is outside of the app directory cone for amd64 and arm64 versions
+of `MSBuild.exe` and 2) Not all resolvers actually live under this directory; the system allows them to be placed anywhere.
+It is unfortunately also not straightforward to add a binding redirect with a [`codeBase`](https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/codebase-element)
+entry pointing to the right assemblies, because this requires knowing the exact assembly versions.
+
+### Microsoft.DotNet.MSBuildSdkResolver
+
+This is the most-commonly-used resolver, capable of resolving "in-box" SDKs that ship with the .NET SDK and .NET SDK workloads. Since the resolver assembly
+is located at a known path relative to MSBuild and has very few dependencies, none of which are used anywhere else, we have decided to
+freeze the version of the resolver plus dependencies, so that their full names can be specified in `MSBuild.exe.config`, e.g.
+
+```xml
+
+
+
+
+```
+
+Additionally, `MSBuild.exe.config` has the following entry, which enables us to refer to the resolver by simple name.
+
+```xml
+
+```
+
+This has a small advantage compared to hardcoding `Microsoft.DotNet.MSBuildSdkResolver, Version=8.0.100.0, Culture=neutral, PublicKeyToken=adb9793829ddae60`
+directly in the code, as it can be modified to work in non-standard environments just by editing the app config appropriately.
+
+The resolver loading logic in MSBuild [has been updated](https://github.com/dotnet/msbuild/pull/9439) to call `Assembly.Load(AssemblyName)` where the `AssemblyName` specifies the
+simple name of the assembly, e.g. `Microsoft.DotNet.MSBuildSdkResolver`, as well as its `CodeBase` (file path). This way the CLR assembly
+loader will try to load the assembly into the default context first - a necessary condition for the native image to be used - and fall back
+to LoadFrom if the simple name wasn't resolved.
+
+### Microsoft.Build.NuGetSdkResolver
+
+The NuGet resolver has many dependencies and its version is frequently changing, so the technique used for `Microsoft.DotNet.MSBuildSdkResolver`
+does not apply in its current state. However, the NuGet team is [looking to address this](https://github.com/NuGet/Home/issues/11441) by:
+
+1) ILMerge'ing the resolver with its dependencies into a single assembly.
+2) Freezing the version of the assembly.
+
+When this happens, the cost of JITting `Microsoft.Build.NuGetSdkResolver` will be eliminated as well.
+
+## NuGet.Frameworks
+
+When evaluating certain property functions, MSBuild requires functionality from `NuGet.Frameworks.dll`, which is not part of MSBuild proper.
+The assembly is loaded lazily from a path calculated based on the environment where MSBuild is running and the functionality is invoked
+via reflection. Similar to the NuGet resolver, the version is changing and it is not easy to know it statically at MSBuild's build time.
+But, since there are only a handful of APIs used by MSBuild and they take simple types such as strings and versions, this has been
+addressed by loading the assembly into a separate AppDomain. The AppDomain's config file is created in memory on the fly to contain the
+right binding redirects, allowing MSBuild to use `Assembly.Load` and get the native image loaded if it exists.
+
+This approach has some small startup cost (building the config, creating AppDomain & a `MarshalByRefObject`) and a small run-time overhead
+of cross-domain calls. The former is orders of magnitude smaller that the startup hit of JITting and the latter is negligible as long as
+the types moved across the AppDomain boundary do not require expensive marshaling.
+
+## Task assemblies
+
+This is the proverbial elephant in the room. MSBuild learns about tasks dynamically as it parses project files. The `UsingTask`
+element tends to specify the `AssemblyFile` attribute, pointing to the task assembly by path. Consequently MSBuild uses
+`Assembly.LoadFrom` and no native images are loaded. Even task assemblies located in the SDK are problematic because MSBuild is
+paired with an SDK on users machine at run-time. Unlike SDK resolvers and NuGet.Frameworks, which are part of the same installation
+unit, this is a true dynamic inter-product dependency. Additionally, the task API is complex and involves a lot of functionality
+provided to tasks via callbacks (e.g. logging) so the overhead of cross-domain calls may be significant. And that's assuming that
+suitable native images exist in the first place, something that both VS and SDK installers would need to handle (task assemblies
+in each installed SDK would need to be NGENed against each installed version of VS).
+
+Hosting task assemblies in separate AppDomains looks like a major piece of work with uncertain outcome. We haven't tried it yet
+and most task code is JITted.