diff --git a/website/docs/development/wrapper_cache.drawio.svg b/website/docs/development/wrapper_cache.drawio.svg
new file mode 100644
index 000000000..bc6303e04
--- /dev/null
+++ b/website/docs/development/wrapper_cache.drawio.svg
@@ -0,0 +1,451 @@
+
\ No newline at end of file
diff --git a/website/docs/development/wrapper_caching.md b/website/docs/development/wrapper_caching.md
new file mode 100644
index 000000000..b7ba9aa7c
--- /dev/null
+++ b/website/docs/development/wrapper_caching.md
@@ -0,0 +1,25 @@
+# Wrapper caching and memory management
+
+
+
+## "Wrapper Keep Alive" case
+
+The goal of the "Wrapper Keep Alive" case is to maintain and "keep alive" wrappers for the life-time of a `QObject` whose life-cycle is under complete control by Qt itself. i.e. Qt may expose the object, but it creates the instance itself and also destroys it later on. This situation applies to `QScreen` and `QClipboard` for example. A common use case for keeping a wrapper alive is to receive and relay signals from a `QObject` back to JS during the object's life-time.
+
+
+
+The WrapperCache (C++) holds strong JS references to the Napi wrapper instances. This keeps them alive. When the core QObject is destroyed the "destroyed" signal is emitted and received by WrapperCache (C++). It then removes the Napi wrapper from its cache and uses a callback function to inform the WrapperCache (JS) about the destruction. WrapperCache (JS) can also perform clean up and null out references to the Napi wrappers. If someone then tries to use a JS side wrapper, then will get a JS side null pointer exception with stacktrace.
+
+**Life-cycle Sequence**
+
+This sequence diagram shows the events when the application calls `QWindow.screen()` to fetch the `QScreen` for the window. The `QScreen` instance is fully created and managed by Qt. Here you can see how the wrapper creation interacts with the JS and C++ side cache classes. You can also see how the wrappers are gracefully shutdown when the core Qt object is destroyed. Any JS side use of the destroyed wrapper / Qt object results in a neat JS side null pointer exception. This is much better than null pointer segfault on the C++ side.
+
+
+
+
+## "Wrapper Recycle" case
+
+A related use case is where we want to "recycle" wrappers and ensure that for a QObject we only have one coresponding JS wrapper active at the same time. For example, repeated calls to `QObject.parent()` should return the same value/object.
+
+Another goal of this use case is to ensure that the unexpected destruction of the underlying QObject is handled in a more graceful and helpful way than just segfaulting the whole application. This requires the tracking of the QObject via its "destroy" signal and using that to communicate back to JS what has happened.
+
diff --git a/website/docs/development/wrapper_keep_alive_seq.png b/website/docs/development/wrapper_keep_alive_seq.png
new file mode 100644
index 000000000..0bbc0adf4
Binary files /dev/null and b/website/docs/development/wrapper_keep_alive_seq.png differ
diff --git a/website/docs/development/wrapper_keep_alive_seq.puml b/website/docs/development/wrapper_keep_alive_seq.puml
new file mode 100644
index 000000000..39175b332
--- /dev/null
+++ b/website/docs/development/wrapper_keep_alive_seq.puml
@@ -0,0 +1,94 @@
+@startuml
+
+skinparam object {
+ backgroundColor White
+ borderColor Black
+ arrowColor Black
+}
+
+skinparam note {
+ backgroundColor LightYellow
+ borderColor Black
+}
+
+hide footbox
+
+title Lifecycle of a Wrapper
+
+participant App as app << ts >> #E3C800
+participant "QWindow.ts" as qwindowts << ts>> #E3C800
+participant "QScreen.ts" as qscreents << ts>> #E3C800
+participant "WrapperCache" as wrappercachets << ts>> #E3C800
+participant "QWindowWrap" as qwindowwrap << cpp >>
+participant "QScreenWrap" as qscreenwrap << cpp >>
+participant "WrapperCache" as wrappercachecpp << cpp >>
+participant "QWindow" as qwindow << cpp >> #D5E8D4
+participant "QScreen" as qscreen << cpp >> #D5E8D4
+
+
+== Wrapper construction ==
+
+activate qscreen
+app --> qwindowts: QWindow.screen()
+qwindowts --> qwindowwrap: screen()
+qwindowwrap --> qwindow: screen()
+qwindow --> qwindowwrap: QScreen instance
+qwindowwrap --> wrappercachecpp: get()
+wrappercachecpp --> qscreenwrap: new()
+activate qscreenwrap
+qscreenwrap --> wrappercachecpp: QScreenWrap instance
+wrappercachecpp --> qscreen: connect to destroy signal
+wrappercachecpp --> qwindowwrap: QScreenWrap instance
+qwindowwrap --> qwindowts: QScreenWrap instance
+qwindowts --> wrappercachets: get(QScreenWrap instance)
+wrappercachets --> qscreents: new(QScreenWrap instance)
+activate qscreents
+qscreents --> wrappercachets: QScreen.ts instance
+wrappercachets --> qwindowts: QScreen.ts instance
+qwindowts --> app: QScreen.ts instance
+
+note across: The app can use the QScreen wrap and run.
+
+== Qt object destruction ==
+note over qscreen
+ Qt decides to destroy
+ the QScreen instance
+end note
+qscreen --> wrappercachecpp: destroy signal
+destroy qscreen
+wrappercachecpp --> wrappercachets: destroy callback
+
+note over wrappercachecpp
+ WrapperCache removes
+ references to the wrapper
+ and Qt object from cache.
+end note
+
+wrappercachets --> qscreents: null the ref to QScreenWrap
+note over wrappercachets
+ WrapperCache.ts removes
+ references to the QScreen.ts
+ instance and QScreenWrap
+end note
+
+destroy qscreenwrap
+note over qscreenwrap
+ V8's GC will destroy
+ this automatically
+end note
+
+app --> qscreents
+note over app
+ Any use of QScreen.ts
+ will hit the null reference
+ and throw a JS exception.
+end note
+app --> qscreents
+
+destroy qscreents
+note over qscreents
+ V8's GC will destroy
+ this automatically
+end note
+
+@enduml