diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp
index 71b997d9e..e10102ee5 100644
--- a/src/query/db_accessor.hpp
+++ b/src/query/db_accessor.hpp
@@ -54,6 +54,10 @@ class EdgeAccessor final {
     return impl_.GetProperty(key, view);
   }
 
+  storage::Result<uint64_t> GetPropertySize(storage::PropertyId key, storage::View view) const {
+    return impl_.GetPropertySize(key, view);
+  }
+
   storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value) {
     return impl_.SetProperty(key, value);
   }
@@ -129,6 +133,10 @@ class VertexAccessor final {
     return impl_.GetProperty(key, view);
   }
 
+  storage::Result<uint64_t> GetPropertySize(storage::PropertyId key, storage::View view) const {
+    return impl_.GetPropertySize(key, view);
+  }
+
   storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value) {
     return impl_.SetProperty(key, value);
   }
@@ -268,6 +276,10 @@ class SubgraphVertexAccessor final {
     return impl_.GetProperty(view, key);
   }
 
+  storage::Result<uint64_t> GetPropertySize(storage::PropertyId key, storage::View view) const {
+    return impl_.GetPropertySize(key, view);
+  }
+
   storage::Gid Gid() const noexcept { return impl_.Gid(); }
 
   storage::Result<size_t> InDegree(storage::View view) const { return impl_.InDegree(view); }
@@ -529,6 +541,10 @@ class DbAccessor final {
 
   storage::PropertyId NameToProperty(const std::string_view name) { return accessor_->NameToProperty(name); }
 
+  std::optional<storage::PropertyId> NameToPropertyIfExists(std::string_view name) const {
+    return accessor_->NameToPropertyIfExists(name);
+  }
+
   storage::LabelId NameToLabel(const std::string_view name) { return accessor_->NameToLabel(name); }
 
   storage::EdgeTypeId NameToEdgeType(const std::string_view name) { return accessor_->NameToEdgeType(name); }
diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp
index ece0aec78..6be8c4837 100644
--- a/src/query/interpret/awesome_memgraph_functions.cpp
+++ b/src/query/interpret/awesome_memgraph_functions.cpp
@@ -442,6 +442,29 @@ TypedValue Size(const TypedValue *args, int64_t nargs, const FunctionContext &ct
   }
 }
 
+TypedValue PropertySize(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
+  FType<Or<Null, Vertex, Edge>, Or<String>>("propertySize", args, nargs);
+
+  auto *dba = ctx.db_accessor;
+
+  const auto &property_name = args[1].ValueString();
+  const auto maybe_property_id = dba->NameToPropertyIfExists(property_name);
+
+  if (!maybe_property_id) {
+    return TypedValue(0, ctx.memory);
+  }
+
+  uint64_t property_size = 0;
+  const auto &graph_entity = args[0];
+  if (graph_entity.IsVertex()) {
+    property_size = graph_entity.ValueVertex().GetPropertySize(*maybe_property_id, ctx.view).GetValue();
+  } else if (graph_entity.IsEdge()) {
+    property_size = graph_entity.ValueEdge().GetPropertySize(*maybe_property_id, ctx.view).GetValue();
+  }
+
+  return TypedValue(static_cast<int64_t>(property_size), ctx.memory);
+}
+
 TypedValue StartNode(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
   FType<Or<Null, Edge>>("startNode", args, nargs);
   if (args[0].IsNull()) return TypedValue(ctx.memory);
@@ -1325,6 +1348,7 @@ std::function<TypedValue(const TypedValue *, int64_t, const FunctionContext &ctx
   if (function_name == "PROPERTIES") return Properties;
   if (function_name == "RANDOMUUID") return RandomUuid;
   if (function_name == "SIZE") return Size;
+  if (function_name == "PROPERTYSIZE") return PropertySize;
   if (function_name == "STARTNODE") return StartNode;
   if (function_name == "TIMESTAMP") return Timestamp;
   if (function_name == "TOBOOLEAN") return ToBoolean;
diff --git a/src/storage/v2/edge_accessor.cpp b/src/storage/v2/edge_accessor.cpp
index 03522ba16..62a9f4bcd 100644
--- a/src/storage/v2/edge_accessor.cpp
+++ b/src/storage/v2/edge_accessor.cpp
@@ -17,6 +17,7 @@
 
 #include "storage/v2/delta.hpp"
 #include "storage/v2/mvcc.hpp"
+#include "storage/v2/property_store.hpp"
 #include "storage/v2/property_value.hpp"
 #include "storage/v2/result.hpp"
 #include "storage/v2/storage.hpp"
@@ -264,6 +265,27 @@ Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property, View view)
   return *std::move(value);
 }
 
+Result<uint64_t> EdgeAccessor::GetPropertySize(PropertyId property, View view) const {
+  if (!storage_->config_.salient.items.properties_on_edges) return 0;
+
+  auto guard = std::shared_lock{edge_.ptr->lock};
+  Delta *delta = edge_.ptr->delta;
+  if (!delta) {
+    return edge_.ptr->properties.PropertySize(property);
+  }
+
+  auto property_result = this->GetProperty(property, view);
+
+  if (property_result.HasError()) {
+    return property_result.GetError();
+  }
+
+  auto property_store = storage::PropertyStore();
+  property_store.SetProperty(property, *property_result);
+
+  return property_store.PropertySize(property);
+};
+
 Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view) const {
   if (!storage_->config_.salient.items.properties_on_edges) return std::map<PropertyId, PropertyValue>{};
   bool exists = true;
diff --git a/src/storage/v2/edge_accessor.hpp b/src/storage/v2/edge_accessor.hpp
index 83a3e549d..6b76ddbe8 100644
--- a/src/storage/v2/edge_accessor.hpp
+++ b/src/storage/v2/edge_accessor.hpp
@@ -82,6 +82,9 @@ class EdgeAccessor final {
   /// @throw std::bad_alloc
   Result<PropertyValue> GetProperty(PropertyId property, View view) const;
 
+  /// Returns the size of the encoded edge property in bytes.
+  Result<uint64_t> GetPropertySize(PropertyId property, View view) const;
+
   /// @throw std::bad_alloc
   Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
 
diff --git a/src/storage/v2/name_id_mapper.hpp b/src/storage/v2/name_id_mapper.hpp
index bb91e3647..d1e8293f9 100644
--- a/src/storage/v2/name_id_mapper.hpp
+++ b/src/storage/v2/name_id_mapper.hpp
@@ -83,6 +83,18 @@ class NameIdMapper {
     return id;
   }
 
+  /// This method unlike NameToId does not insert the new property id if not found
+  /// but just returns either std::nullopt or the value of the property id if it
+  /// finds it.
+  virtual std::optional<uint64_t> NameToIdIfExists(const std::string_view name) {
+    auto name_to_id_acc = name_to_id_.access();
+    auto found = name_to_id_acc.find(name);
+    if (found == name_to_id_acc.end()) {
+      return std::nullopt;
+    }
+    return found->id;
+  }
+
   // NOTE: Currently this function returns a `const std::string &` instead of a
   // `std::string` to avoid making unnecessary copies of the string.
   // Usually, this wouldn't be correct because the accessor to the
diff --git a/src/storage/v2/property_store.cpp b/src/storage/v2/property_store.cpp
index 427998fbe..e6e4dbbaf 100644
--- a/src/storage/v2/property_store.cpp
+++ b/src/storage/v2/property_store.cpp
@@ -93,6 +93,19 @@ enum class Size : uint8_t {
   INT64 = 0x03,
 };
 
+uint64_t SizeToByteSize(Size size) {
+  switch (size) {
+    case Size::INT8:
+      return 1;
+    case Size::INT16:
+      return 2;
+    case Size::INT32:
+      return 4;
+    case Size::INT64:
+      return 8;
+  }
+}
+
 // All of these values must have the lowest 4 bits set to zero because they are
 // used to store two `Size` values as described in the comment above.
 enum class Type : uint8_t {
@@ -486,6 +499,27 @@ std::optional<TemporalData> DecodeTemporalData(Reader &reader) {
   return TemporalData{static_cast<TemporalType>(*type_value), *microseconds_value};
 }
 
+std::optional<uint64_t> DecodeTemporalDataSize(Reader &reader) {
+  uint64_t temporal_data_size = 0;
+
+  auto metadata = reader.ReadMetadata();
+  if (!metadata || metadata->type != Type::TEMPORAL_DATA) return std::nullopt;
+
+  temporal_data_size += 1;
+
+  auto type_value = reader.ReadUint(metadata->id_size);
+  if (!type_value) return std::nullopt;
+
+  temporal_data_size += SizeToByteSize(metadata->id_size);
+
+  auto microseconds_value = reader.ReadInt(metadata->payload_size);
+  if (!microseconds_value) return std::nullopt;
+
+  temporal_data_size += SizeToByteSize(metadata->payload_size);
+
+  return temporal_data_size;
+}
+
 }  // namespace
 
 // Function used to decode a PropertyValue from a byte stream.
@@ -572,6 +606,92 @@ std::optional<TemporalData> DecodeTemporalData(Reader &reader) {
   }
 }
 
+[[nodiscard]] bool DecodePropertyValueSize(Reader *reader, Type type, Size payload_size, uint64_t &property_size) {
+  switch (type) {
+    case Type::EMPTY: {
+      return false;
+    }
+    case Type::NONE:
+    case Type::BOOL: {
+      return true;
+    }
+    case Type::INT: {
+      reader->ReadInt(payload_size);
+      property_size += SizeToByteSize(payload_size);
+      return true;
+    }
+    case Type::DOUBLE: {
+      reader->ReadDouble(payload_size);
+      property_size += SizeToByteSize(payload_size);
+      return true;
+    }
+    case Type::STRING: {
+      auto size = reader->ReadUint(payload_size);
+      if (!size) return false;
+      property_size += SizeToByteSize(payload_size);
+
+      std::string str_v(*size, '\0');
+      if (!reader->SkipBytes(*size)) return false;
+      property_size += *size;
+
+      return true;
+    }
+    case Type::LIST: {
+      auto size = reader->ReadUint(payload_size);
+      if (!size) return false;
+
+      uint64_t list_property_size = SizeToByteSize(payload_size);
+
+      for (uint64_t i = 0; i < *size; ++i) {
+        auto metadata = reader->ReadMetadata();
+        if (!metadata) return false;
+
+        list_property_size += 1;
+        if (!DecodePropertyValueSize(reader, metadata->type, metadata->payload_size, list_property_size)) return false;
+      }
+
+      property_size += list_property_size;
+      return true;
+    }
+    case Type::MAP: {
+      auto size = reader->ReadUint(payload_size);
+      if (!size) return false;
+
+      uint64_t map_property_size = SizeToByteSize(payload_size);
+
+      for (uint64_t i = 0; i < *size; ++i) {
+        auto metadata = reader->ReadMetadata();
+        if (!metadata) return false;
+
+        map_property_size += 1;
+
+        auto key_size = reader->ReadUint(metadata->id_size);
+        if (!key_size) return false;
+
+        map_property_size += SizeToByteSize(metadata->id_size);
+
+        std::string key(*key_size, '\0');
+        if (!reader->ReadBytes(key.data(), *key_size)) return false;
+
+        map_property_size += *key_size;
+
+        if (!DecodePropertyValueSize(reader, metadata->type, metadata->payload_size, map_property_size)) return false;
+      }
+
+      property_size += map_property_size;
+      return true;
+    }
+
+    case Type::TEMPORAL_DATA: {
+      const auto maybe_temporal_data_size = DecodeTemporalDataSize(*reader);
+      if (!maybe_temporal_data_size) return false;
+
+      property_size += *maybe_temporal_data_size;
+      return true;
+    }
+  }
+}
+
 // Function used to skip a PropertyValue from a byte stream.
 //
 // @sa ComparePropertyValue
@@ -788,6 +908,27 @@ enum class ExpectedPropertyStatus {
                                                      : ExpectedPropertyStatus::GREATER;
 }
 
+[[nodiscard]] ExpectedPropertyStatus DecodeExpectedPropertySize(Reader *reader, PropertyId expected_property,
+                                                                uint64_t &size) {
+  auto metadata = reader->ReadMetadata();
+  if (!metadata) return ExpectedPropertyStatus::MISSING_DATA;
+
+  auto property_id = reader->ReadUint(metadata->id_size);
+  if (!property_id) return ExpectedPropertyStatus::MISSING_DATA;
+
+  if (*property_id == expected_property.AsUint()) {
+    // Add one byte for reading metadata + add the number of bytes for the property key
+    size += (1 + SizeToByteSize(metadata->id_size));
+    if (!DecodePropertyValueSize(reader, metadata->type, metadata->payload_size, size))
+      return ExpectedPropertyStatus::MISSING_DATA;
+    return ExpectedPropertyStatus::EQUAL;
+  }
+  // Don't load the value if this isn't the expected property.
+  if (!SkipPropertyValue(reader, metadata->type, metadata->payload_size)) return ExpectedPropertyStatus::MISSING_DATA;
+  return (*property_id < expected_property.AsUint()) ? ExpectedPropertyStatus::SMALLER
+                                                     : ExpectedPropertyStatus::GREATER;
+}
+
 // Function used to check a property exists (PropertyId) from a byte stream.
 // It will skip the encoded PropertyValue.
 //
@@ -875,6 +1016,13 @@ enum class ExpectedPropertyStatus {
   }
 }
 
+[[nodiscard]] ExpectedPropertyStatus FindSpecificPropertySize(Reader *reader, PropertyId property, uint64_t &size) {
+  ExpectedPropertyStatus ret = ExpectedPropertyStatus::SMALLER;
+  while ((ret = DecodeExpectedPropertySize(reader, property, size)) == ExpectedPropertyStatus::SMALLER) {
+  }
+  return ret;
+}
+
 // Function used to find if property is set. It relies on the fact that the properties
 // are sorted (by ID) in the buffer.
 //
@@ -983,6 +1131,31 @@ std::pair<uint64_t, uint8_t *> GetSizeData(const uint8_t *buffer) {
   return {size, data};
 }
 
+struct BufferInfo {
+  uint64_t size;
+  uint8_t *data{nullptr};
+  bool in_local_buffer;
+};
+
+template <size_t N>
+BufferInfo GetBufferInfo(const uint8_t (&buffer)[N]) {
+  uint64_t size = 0;
+  const uint8_t *data = nullptr;
+  bool in_local_buffer = false;
+  std::tie(size, data) = GetSizeData(buffer);
+  if (size % 8 != 0) {
+    // We are storing the data in the local buffer.
+    size = sizeof(buffer) - 1;
+    data = &buffer[1];
+    in_local_buffer = true;
+  }
+
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+  auto *non_const_data = const_cast<uint8_t *>(data);
+
+  return {size, non_const_data, in_local_buffer};
+}
+
 void SetSizeData(uint8_t *buffer, uint64_t size, uint8_t *data) {
   memcpy(buffer, &size, sizeof(uint64_t));
   memcpy(buffer + sizeof(uint64_t), &data, sizeof(uint8_t *));
@@ -1023,30 +1196,27 @@ PropertyStore::~PropertyStore() {
 }
 
 PropertyValue PropertyStore::GetProperty(PropertyId property) const {
-  uint64_t size;
-  const uint8_t *data;
-  std::tie(size, data) = GetSizeData(buffer_);
-  if (size % 8 != 0) {
-    // We are storing the data in the local buffer.
-    size = sizeof(buffer_) - 1;
-    data = &buffer_[1];
-  }
-  Reader reader(data, size);
+  BufferInfo buffer_info = GetBufferInfo(buffer_);
+  Reader reader(buffer_info.data, buffer_info.size);
+
   PropertyValue value;
   if (FindSpecificProperty(&reader, property, value) != ExpectedPropertyStatus::EQUAL) return {};
   return value;
 }
 
+uint64_t PropertyStore::PropertySize(PropertyId property) const {
+  auto data_size_localbuffer = GetBufferInfo(buffer_);
+  Reader reader(data_size_localbuffer.data, data_size_localbuffer.size);
+
+  uint64_t property_size = 0;
+  if (FindSpecificPropertySize(&reader, property, property_size) != ExpectedPropertyStatus::EQUAL) return 0;
+  return property_size;
+}
+
 bool PropertyStore::HasProperty(PropertyId property) const {
-  uint64_t size;
-  const uint8_t *data;
-  std::tie(size, data) = GetSizeData(buffer_);
-  if (size % 8 != 0) {
-    // We are storing the data in the local buffer.
-    size = sizeof(buffer_) - 1;
-    data = &buffer_[1];
-  }
-  Reader reader(data, size);
+  BufferInfo buffer_info = GetBufferInfo(buffer_);
+  Reader reader(buffer_info.data, buffer_info.size);
+
   return ExistsSpecificProperty(&reader, property) == ExpectedPropertyStatus::EQUAL;
 }
 
@@ -1081,32 +1251,20 @@ std::optional<std::vector<PropertyValue>> PropertyStore::ExtractPropertyValues(
 }
 
 bool PropertyStore::IsPropertyEqual(PropertyId property, const PropertyValue &value) const {
-  uint64_t size;
-  const uint8_t *data;
-  std::tie(size, data) = GetSizeData(buffer_);
-  if (size % 8 != 0) {
-    // We are storing the data in the local buffer.
-    size = sizeof(buffer_) - 1;
-    data = &buffer_[1];
-  }
-  Reader reader(data, size);
+  BufferInfo buffer_info = GetBufferInfo(buffer_);
+  Reader reader(buffer_info.data, buffer_info.size);
+
   auto info = FindSpecificPropertyAndBufferInfo(&reader, property);
   if (info.property_size == 0) return value.IsNull();
-  Reader prop_reader(data + info.property_begin, info.property_size);
+  Reader prop_reader(buffer_info.data + info.property_begin, info.property_size);
   if (!CompareExpectedProperty(&prop_reader, property, value)) return false;
   return prop_reader.GetPosition() == info.property_size;
 }
 
 std::map<PropertyId, PropertyValue> PropertyStore::Properties() const {
-  uint64_t size;
-  const uint8_t *data;
-  std::tie(size, data) = GetSizeData(buffer_);
-  if (size % 8 != 0) {
-    // We are storing the data in the local buffer.
-    size = sizeof(buffer_) - 1;
-    data = &buffer_[1];
-  }
-  Reader reader(data, size);
+  BufferInfo buffer_info = GetBufferInfo(buffer_);
+  Reader reader(buffer_info.data, buffer_info.size);
+
   std::map<PropertyId, PropertyValue> props;
   while (true) {
     PropertyValue value;
@@ -1340,33 +1498,20 @@ bool PropertyStore::InitProperties(std::vector<std::pair<storage::PropertyId, st
 }
 
 bool PropertyStore::ClearProperties() {
-  bool in_local_buffer = false;
-  uint64_t size;
-  uint8_t *data;
-  std::tie(size, data) = GetSizeData(buffer_);
-  if (size % 8 != 0) {
-    // We are storing the data in the local buffer.
-    size = sizeof(buffer_) - 1;
-    data = &buffer_[1];
-    in_local_buffer = true;
-  }
-  if (!size) return false;
-  if (!in_local_buffer) delete[] data;
+  BufferInfo buffer_info = GetBufferInfo(buffer_);
+
+  if (!buffer_info.size) return false;
+  if (!buffer_info.in_local_buffer) delete[] buffer_info.data;
   SetSizeData(buffer_, 0, nullptr);
   return true;
 }
 
 std::string PropertyStore::StringBuffer() const {
-  uint64_t size = 0;
-  const uint8_t *data = nullptr;
-  std::tie(size, data) = GetSizeData(buffer_);
-  if (size % 8 != 0) {  // We are storing the data in the local buffer.
-    size = sizeof(buffer_) - 1;
-    data = &buffer_[1];
-  }
-  std::string arr(size, ' ');
-  for (uint i = 0; i < size; ++i) {
-    arr[i] = static_cast<char>(data[i]);
+  BufferInfo buffer_info = GetBufferInfo(buffer_);
+
+  std::string arr(buffer_info.size, ' ');
+  for (uint i = 0; i < buffer_info.size; ++i) {
+    arr[i] = static_cast<char>(buffer_info.data[i]);
   }
   return arr;
 }
diff --git a/src/storage/v2/property_store.hpp b/src/storage/v2/property_store.hpp
index c217cbd81..eee83f5df 100644
--- a/src/storage/v2/property_store.hpp
+++ b/src/storage/v2/property_store.hpp
@@ -45,6 +45,11 @@ class PropertyStore {
   /// @throw std::bad_alloc
   PropertyValue GetProperty(PropertyId property) const;
 
+  /// Returns the size of the encoded property in bytes.
+  /// Returns 0 if the property does not exist.
+  /// The time complexity of this function is O(n).
+  uint64_t PropertySize(PropertyId property) const;
+
   /// Checks whether the property `property` exists in the store. The time
   /// complexity of this function is O(n).
   bool HasProperty(PropertyId property) const;
diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp
index a096f27fd..722867f74 100644
--- a/src/storage/v2/storage.hpp
+++ b/src/storage/v2/storage.hpp
@@ -250,6 +250,10 @@ class Storage {
 
     PropertyId NameToProperty(std::string_view name) { return storage_->NameToProperty(name); }
 
+    std::optional<PropertyId> NameToPropertyIfExists(std::string_view name) const {
+      return storage_->NameToPropertyIfExists(name);
+    }
+
     EdgeTypeId NameToEdgeType(std::string_view name) { return storage_->NameToEdgeType(name); }
 
     StorageMode GetCreationStorageMode() const noexcept;
@@ -318,6 +322,14 @@ class Storage {
     return PropertyId::FromUint(name_id_mapper_->NameToId(name));
   }
 
+  std::optional<PropertyId> NameToPropertyIfExists(std::string_view name) const {
+    const auto id = name_id_mapper_->NameToIdIfExists(name);
+    if (!id) {
+      return std::nullopt;
+    }
+    return PropertyId::FromUint(*id);
+  }
+
   EdgeTypeId NameToEdgeType(const std::string_view name) const {
     return EdgeTypeId::FromUint(name_id_mapper_->NameToId(name));
   }
diff --git a/src/storage/v2/vertex_accessor.cpp b/src/storage/v2/vertex_accessor.cpp
index ff5062444..ef0a6ab3e 100644
--- a/src/storage/v2/vertex_accessor.cpp
+++ b/src/storage/v2/vertex_accessor.cpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Memgraph Ltd.
+// Copyright 2024 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -438,6 +438,26 @@ Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view
   return std::move(value);
 }
 
+Result<uint64_t> VertexAccessor::GetPropertySize(PropertyId property, View view) const {
+  {
+    auto guard = std::shared_lock{vertex_->lock};
+    Delta *delta = vertex_->delta;
+    if (!delta) {
+      return vertex_->properties.PropertySize(property);
+    }
+  }
+
+  auto property_result = this->GetProperty(property, view);
+  if (property_result.HasError()) {
+    return property_result.GetError();
+  }
+
+  auto property_store = storage::PropertyStore();
+  property_store.SetProperty(property, *property_result);
+
+  return property_store.PropertySize(property);
+};
+
 Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view) const {
   bool exists = true;
   bool deleted = false;
diff --git a/src/storage/v2/vertex_accessor.hpp b/src/storage/v2/vertex_accessor.hpp
index 0e5972d14..18fad3dcc 100644
--- a/src/storage/v2/vertex_accessor.hpp
+++ b/src/storage/v2/vertex_accessor.hpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Memgraph Ltd.
+// Copyright 2024 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -80,6 +80,9 @@ class VertexAccessor final {
   /// @throw std::bad_alloc
   Result<PropertyValue> GetProperty(PropertyId property, View view) const;
 
+  /// Returns the size of the encoded vertex property in bytes.
+  Result<uint64_t> GetPropertySize(PropertyId property, View view) const;
+
   /// @throw std::bad_alloc
   Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
 
diff --git a/tests/e2e/CMakeLists.txt b/tests/e2e/CMakeLists.txt
index 7e555398e..b8fee9940 100644
--- a/tests/e2e/CMakeLists.txt
+++ b/tests/e2e/CMakeLists.txt
@@ -76,6 +76,7 @@ add_subdirectory(queries)
 add_subdirectory(query_modules_storage_modes)
 add_subdirectory(garbage_collection)
 add_subdirectory(query_planning)
+add_subdirectory(awesome_functions)
 
 if (MG_EXPERIMENTAL_HIGH_AVAILABILITY)
   add_subdirectory(high_availability_experimental)
diff --git a/tests/e2e/awesome_functions/CMakeLists.txt b/tests/e2e/awesome_functions/CMakeLists.txt
new file mode 100644
index 000000000..9d6e0143b
--- /dev/null
+++ b/tests/e2e/awesome_functions/CMakeLists.txt
@@ -0,0 +1,6 @@
+function(copy_awesome_functions_e2e_python_files FILE_NAME)
+    copy_e2e_python_files(awesome_functions ${FILE_NAME})
+endfunction()
+
+copy_awesome_functions_e2e_python_files(common.py)
+copy_awesome_functions_e2e_python_files(awesome_functions.py)
diff --git a/tests/e2e/awesome_functions/awesome_functions.py b/tests/e2e/awesome_functions/awesome_functions.py
new file mode 100644
index 000000000..9761708ed
--- /dev/null
+++ b/tests/e2e/awesome_functions/awesome_functions.py
@@ -0,0 +1,269 @@
+# Copyright 2023 Memgraph Ltd.
+#
+# Use of this software is governed by the Business Source License
+# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
+# License, and you may not use this file except in compliance with the Business Source License.
+#
+# As of the Change Date specified in that file, in accordance with
+# the Business Source License, use of this software will be governed
+# by the Apache License, Version 2.0, included in the file
+# licenses/APL.txt.
+
+import sys
+
+import pytest
+from common import get_bytes, memgraph
+
+
+def test_property_size_on_null_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.null_prop = null;
+        """
+    )
+
+    null_bytes = get_bytes(memgraph, "null_prop")
+
+    # No property stored, no bytes allocated
+    assert null_bytes == 0
+
+
+def test_property_size_on_bool_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.bool_prop = True;
+        """
+    )
+
+    bool_bytes = get_bytes(memgraph, "bool_prop")
+
+    # 1 byte metadata, 1 byte prop id, but value is encoded in the metadata
+    assert bool_bytes == 2
+
+
+def test_property_size_on_one_byte_int_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.S_int_prop = 4;
+        """
+    )
+
+    s_int_bytes = get_bytes(memgraph, "S_int_prop")
+
+    # 1 byte metadata, 1 byte prop id + payload size 1 byte to store the int
+    assert s_int_bytes == 3
+
+
+def test_property_size_on_two_byte_int_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.M_int_prop = 500;
+        """
+    )
+
+    m_int_bytes = get_bytes(memgraph, "M_int_prop")
+
+    # 1 byte metadata, 1 byte prop id + payload size 2 bytes to store the int
+    assert m_int_bytes == 4
+
+
+def test_property_size_on_four_byte_int_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.L_int_prop = 1000000000;
+        """
+    )
+
+    l_int_bytes = get_bytes(memgraph, "L_int_prop")
+
+    # 1 byte metadata, 1 byte prop id + payload size 4 bytes to store the int
+    assert l_int_bytes == 6
+
+
+def test_property_size_on_eight_byte_int_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.XL_int_prop = 1000000000000;
+        """
+    )
+
+    xl_int_bytes = get_bytes(memgraph, "XL_int_prop")
+
+    # 1 byte metadata, 1 byte prop id + payload size 8 bytes to store the int
+    assert xl_int_bytes == 10
+
+
+def test_property_size_on_float_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.float_prop = 4.0;
+        """
+    )
+
+    float_bytes = get_bytes(memgraph, "float_prop")
+
+    # 1 byte metadata, 1 byte prop id + payload size 8 bytes to store the float
+    assert float_bytes == 10
+
+
+def test_property_size_on_string_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.str_prop = 'str_value';
+        """
+    )
+
+    str_bytes = get_bytes(memgraph, "str_prop")
+
+    # 1 byte metadata
+    # 1 byte prop id
+    #   - the payload size contains the amount of bytes stored for the size in the next sequence
+    # X bytes for the length of the string (1, 2, 4 or 8 bytes) -> "str_value" has 1 byte for the length of 9
+    # Y bytes for the string content -> 9 bytes for "str_value"
+    assert str_bytes == 12
+
+
+def test_property_size_on_list_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.list_prop = [1, 2, 3];
+        """
+    )
+
+    list_bytes = get_bytes(memgraph, "list_prop")
+
+    # 1 byte metadata
+    # 1 byte prop id
+    #   - the payload size contains the amount of bytes stored for the size of the list
+    # X bytes for the size of the list (1, 2, 4 or 8 bytes)
+    # for each list element:
+    #   - 1 byte for the metadata
+    #   - the amount of bytes for the payload of the type (a small int is 1 additional byte)
+    # in this case 1 + 1 + 3 * (1 + 1)
+    assert list_bytes == 9
+
+
+def test_property_size_on_map_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET  n.map_prop = {key1: 'value', key2: 4};
+        """
+    )
+
+    map_bytes = get_bytes(memgraph, "map_prop")
+
+    # 1 byte metadata
+    # 1 byte prop id
+    #   - the payload size contains the amount of bytes stored for the size of the map
+    # X bytes for the size of the map (1, 2, 4 or 8 bytes - in this case 1)
+    # for every map element:
+    #   - 1 byte for metadata
+    #   - 1, 2, 4 or 8 bytes for the key length (read from the metadata payload) -> this case 1
+    #   - Y bytes for the key content -> this case 4
+    #   - Z amount of bytes for the type
+    #       - for 'value' -> 1 byte for size and 5 for length
+    #       - for 4 -> 1 byte for content read from payload
+    # total: 1 + 1 + (1 + 1 + 4 + (1 + 5)) + (1 + 1 + 4 + (1))
+    assert map_bytes == 22
+
+
+def test_property_size_on_date_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.date_prop = date('2023-01-01');
+        """
+    )
+
+    date_bytes = get_bytes(memgraph, "date_prop")
+
+    # 1 byte metadata (to see that it's temporal data)
+    # 1 byte prop id
+    # 1 byte metadata
+    #   - type is again the same
+    #   - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
+    #   - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
+    assert date_bytes == 12
+
+
+def test_property_size_on_local_time_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.localtime_prop = localtime('23:00:00');
+        """
+    )
+
+    local_time_bytes = get_bytes(memgraph, "localtime_prop")
+
+    # 1 byte metadata (to see that it's temporal data)
+    # 1 byte prop id
+    # 1 byte metadata
+    #   - type is again the same
+    #   - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
+    #   - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
+    assert local_time_bytes == 12
+
+
+def test_property_size_on_local_date_time_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.localdatetime_prop = localdatetime('2022-01-01T23:00:00');
+        """
+    )
+
+    local_date_time_bytes = get_bytes(memgraph, "localdatetime_prop")
+
+    # 1 byte metadata (to see that it's temporal data)
+    # 1 byte prop id
+    # 1 byte metadata
+    #   - type is again the same
+    #   - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
+    #   - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
+    assert local_date_time_bytes == 12
+
+
+def test_property_size_on_duration_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node)
+        SET n.duration_prop = duration('P5DT2M2.33S');
+        """
+    )
+
+    duration_bytes = get_bytes(memgraph, "duration_prop")
+
+    # 1 byte metadata (to see that it's temporal data)
+    # 1 byte prop id
+    # 1 byte metadata
+    #   - type is again the same
+    #   - id field contains the length of the specific temporal type (1, 2, 4 or 8 bytes) -> probably always 1
+    #   - payload field contains the length of the microseconds (1, 2, 4, or 8 bytes) -> probably always 8
+    assert duration_bytes == 12
+
+
+def test_property_size_on_nonexistent_prop(memgraph):
+    memgraph.execute(
+        """
+        CREATE (n:Node);
+        """
+    )
+
+    nonexistent_bytes = get_bytes(memgraph, "nonexistent_prop")
+
+    assert nonexistent_bytes == 0
+
+
+if __name__ == "__main__":
+    sys.exit(pytest.main([__file__, "-rA"]))
diff --git a/tests/e2e/awesome_functions/common.py b/tests/e2e/awesome_functions/common.py
new file mode 100644
index 000000000..14f272c23
--- /dev/null
+++ b/tests/e2e/awesome_functions/common.py
@@ -0,0 +1,29 @@
+# Copyright 2023 Memgraph Ltd.
+#
+# Use of this software is governed by the Business Source License
+# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
+# License, and you may not use this file except in compliance with the Business Source License.
+#
+# As of the Change Date specified in that file, in accordance with
+# the Business Source License, use of this software will be governed
+# by the Apache License, Version 2.0, included in the file
+# licenses/APL.txt.
+
+import pytest
+from gqlalchemy import Memgraph
+
+
+@pytest.fixture
+def memgraph(**kwargs) -> Memgraph:
+    memgraph = Memgraph()
+
+    yield memgraph
+
+    memgraph.drop_indexes()
+    memgraph.ensure_constraints([])
+    memgraph.drop_database()
+
+
+def get_bytes(memgraph, prop_name):
+    res = list(memgraph.execute_and_fetch(f"MATCH (n) RETURN propertySize(n, '{prop_name}') AS size"))
+    return res[0]["size"]
diff --git a/tests/e2e/awesome_functions/workloads.yaml b/tests/e2e/awesome_functions/workloads.yaml
new file mode 100644
index 000000000..37e5e8813
--- /dev/null
+++ b/tests/e2e/awesome_functions/workloads.yaml
@@ -0,0 +1,14 @@
+awesome_functions_cluster: &awesome_functions_cluster
+  cluster:
+    main:
+      args: ["--bolt-port", "7687", "--log-level=TRACE"]
+      log_file: "awesome_functions.log"
+      setup_queries: []
+      validation_queries: []
+
+
+workloads:
+  - name: "Awesome Functions"
+    binary: "tests/e2e/pytest_runner.sh"
+    args: ["awesome_functions/awesome_functions.py"]
+    <<: *awesome_functions_cluster