diff --git a/storage/edge.hpp b/storage/edge.hpp
new file mode 100644
index 000000000..fcd65c66e
--- /dev/null
+++ b/storage/edge.hpp
@@ -0,0 +1,16 @@
+#ifndef MEMGRAPH_DATA_MODEL_EDGE_HPP
+#define MEMGRAPH_DATA_MODEL_EDGE_HPP
+
+#include "json/all.hpp"
+#include "record.hpp"
+
+struct Node;
+
+struct Edge : Record
+{
+    Node* to;
+
+    std::string data;
+};
+
+#endif
diff --git a/storage/graph.hpp b/storage/graph.hpp
new file mode 100644
index 000000000..b74f73ed9
--- /dev/null
+++ b/storage/graph.hpp
@@ -0,0 +1,13 @@
+#ifndef MEMGRAPH_DATA_MODEL_GRAPH_HPP
+#define MEMGRAPH_DATA_MODEL_GRAPH_HPP
+
+#include <vector>
+
+#include "node.hpp"
+#include "edge.hpp"
+
+struct Graph
+{
+}
+
+#endif
diff --git a/storage/json/all.hpp b/storage/json/all.hpp
new file mode 100644
index 000000000..d6bf229a4
--- /dev/null
+++ b/storage/json/all.hpp
@@ -0,0 +1,14 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_ALL_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_ALL_HPP
+
+#include "array.hpp"
+#include "bool.hpp"
+#include "integral.hpp"
+#include "json.hpp"
+#include "null.hpp"
+#include "object.hpp"
+#include "primitive.hpp"
+#include "real.hpp"
+#include "string.hpp"
+
+#endif
diff --git a/storage/json/array.hpp b/storage/json/array.hpp
new file mode 100644
index 000000000..0ec2187f5
--- /dev/null
+++ b/storage/json/array.hpp
@@ -0,0 +1,84 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_ARRAY_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_ARRAY_HPP
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#include "utilities/string/intercalate.hpp"
+
+#include "json.hpp"
+
+namespace json
+{
+
+class Array final : public Json
+{
+public:
+    Array() {}
+
+    template <typename It>
+    Array(It first, It last)
+        : elements(first, last) {}
+
+    Array(std::initializer_list<spJson> elements)
+        : elements(elements) {}
+
+    virtual bool is_array() const;
+
+    size_t size() const;
+
+    Array& push(const std::shared_ptr<Json>& element);
+
+    const spJson& operator[](size_t i) const;
+          spJson  operator[](size_t i);
+
+    virtual operator std::string() const;
+
+private:
+    std::vector<spJson> elements;
+};
+
+bool Array::is_array() const
+{
+    return true;
+}
+
+size_t Array::size() const
+{
+    return elements.size();
+}
+
+Array& Array::push(const spJson& element)
+{
+    assert(element);
+
+    elements.push_back(element);
+    return *this;
+}
+
+const spJson& Array::operator[](size_t i) const
+{
+    return elements[i];
+}
+
+spJson Array::operator[](size_t i)
+{
+    return elements[i];
+}
+
+Array::operator std::string() const
+{
+    std::vector<std::string> xs;
+
+    std::transform(elements.begin(), elements.end(), std::back_inserter(xs),
+        [](const spJson& element) {
+            return static_cast<std::string>(*element);
+        });
+
+    return "[" + utils::intercalate(xs.begin(), xs.end(), ",") + "]";
+}
+
+}
+
+#endif  
diff --git a/storage/json/bool.hpp b/storage/json/bool.hpp
new file mode 100644
index 000000000..545386062
--- /dev/null
+++ b/storage/json/bool.hpp
@@ -0,0 +1,33 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_BOOL_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_BOOL_HPP
+
+#include "primitive.hpp"
+
+namespace json {
+
+class Bool final : public Primitive<bool> 
+{
+public:
+    Bool() {}
+
+    Bool(bool value) 
+        : Primitive<bool>(value) {}
+    
+    virtual bool is_boolean() const;
+
+    virtual operator std::string() const;
+};
+
+bool Bool::is_boolean() const
+{
+    return true;
+}
+
+Bool::operator std::string() const
+{
+    return value == true ? "true" : "false";
+}
+
+}
+
+#endif
diff --git a/storage/json/integral.hpp b/storage/json/integral.hpp
new file mode 100644
index 000000000..2467f8742
--- /dev/null
+++ b/storage/json/integral.hpp
@@ -0,0 +1,33 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_INTEGRAL_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_INTEGRAL_HPP
+
+#include "primitive.hpp"
+
+namespace json {
+
+class Integral final : public Primitive<int64_t>
+{
+public:
+    Integral() {}
+
+    Integral(int64_t value)
+        : Primitive<int64_t>(value) {}
+
+    virtual bool is_integral() const;
+
+    virtual operator std::string() const;  
+};
+
+bool Integral::is_integral() const
+{
+    return true;
+}
+
+Integral::operator std::string() const
+{
+    return std::to_string(value);
+}
+
+}
+
+#endif
diff --git a/storage/json/json.hpp b/storage/json/json.hpp
new file mode 100644
index 000000000..dc9784108
--- /dev/null
+++ b/storage/json/json.hpp
@@ -0,0 +1,47 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_JSON_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_JSON_HPP
+
+#include <initializer_list>
+#include <string>
+#include <memory>
+
+namespace json {
+
+class Json;
+
+typedef std::shared_ptr<Json> spJson;
+
+class Json
+{
+public:
+    Json() {}
+    virtual ~Json() {}
+
+    virtual bool is_object()   const { return false; }
+    virtual bool is_array()    const { return false; }
+    virtual bool is_real()     const { return false; }
+    virtual bool is_integral() const { return false; }
+    virtual bool is_boolean()  const { return false; }
+    virtual bool is_null()     const { return false; }
+
+    template <typename T> T& as();
+    template <typename T> const T& as() const;
+
+    virtual operator std::string() const = 0;
+};
+
+template <typename T>
+T& Json::as()
+{
+    return *dynamic_cast<T*>(this);
+}
+
+template <typename T>
+const T& Json::as() const
+{
+    return *dynamic_cast<T*>(this);
+}
+
+}
+
+#endif
diff --git a/storage/json/null.hpp b/storage/json/null.hpp
new file mode 100644
index 000000000..3a50bf867
--- /dev/null
+++ b/storage/json/null.hpp
@@ -0,0 +1,30 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_NULL_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_NULL_HPP
+
+#include "json.hpp"
+
+namespace json {
+
+class Null final : public Json 
+{
+public:
+    Null() {}
+    
+    virtual bool is_null() const;
+
+    virtual operator std::string() const;
+};
+
+bool Null::is_null() const
+{
+    return true;
+}
+
+Null::operator std::string() const
+{
+    return "null";
+}
+    
+}
+
+#endif
diff --git a/storage/json/object.hpp b/storage/json/object.hpp
new file mode 100644
index 000000000..ee7b13ce1
--- /dev/null
+++ b/storage/json/object.hpp
@@ -0,0 +1,106 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_OBJECT_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_OBJECT_HPP
+
+#include <iostream>
+
+#include <functional>
+#include <sstream>
+#include <cassert>
+#include <vector>
+#include <map>
+
+#include "utilities/string/intercalate.hpp"
+
+#include "json.hpp"
+
+namespace json {
+
+typedef std::pair<const std::string, spJson> const_kv_pair_t;
+typedef std::pair<std::string, spJson> kv_pair_t;
+
+class Object;
+
+typedef std::shared_ptr<Object> spObject;
+
+class Object : public Json
+{
+public:
+    Object() {}
+
+    Object(std::initializer_list<const_kv_pair_t> elements)
+        : props(elements) {}
+
+    virtual bool is_object() const;
+
+    const spJson& at(const std::string& key) const;
+          spJson  at(const std::string& key);
+
+    const spJson& operator[](const std::string& key) const;
+          spJson  operator[](const std::string& key);
+
+    Object& put(const std::string& key, spJson value);
+
+    Object& operator<<(const kv_pair_t& kv_pair);
+
+    virtual operator std::string() const;
+
+protected:
+    std::map<std::string, spJson> props;
+};
+
+bool Object::is_object() const
+{
+    return true;
+}
+
+const spJson& Object::at(const std::string& key) const
+{
+    return props.at(key);
+}
+
+spJson Object::at(const std::string& key)
+{
+    return props.at(key);
+}
+
+const spJson& Object::operator[](const std::string& key) const
+{
+    return this->at(key);
+}
+
+spJson Object::operator[](const std::string& key)
+{
+    return this->at(key);
+}
+
+Object& Object::put(const std::string& key, spJson value)
+{
+    assert(value);
+
+    props[key] = value;
+    return *this;
+}
+
+Object& Object::operator<<(const kv_pair_t& kv_pair)
+{
+    return this->put(std::get<0>(kv_pair), std::get<1>(kv_pair));
+}
+
+Object::operator std::string() const
+{
+    if(props.empty())
+        return "{}";
+
+    std::vector<std::string> xs;
+
+    std::transform(props.begin(), props.end(), std::back_inserter(xs),
+        [](const kv_pair_t& kvp) {
+            return "\"" + kvp.first + "\":" + static_cast<std::string>(*kvp.second);
+        });
+
+    return "{" + utils::intercalate(xs.begin(), xs.end(), ",") + "}";
+}
+
+}
+
+#endif
diff --git a/storage/json/primitive.hpp b/storage/json/primitive.hpp
new file mode 100644
index 000000000..cf4a9451b
--- /dev/null
+++ b/storage/json/primitive.hpp
@@ -0,0 +1,29 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_PRIMITIVE_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_PRIMITIVE_HPP
+
+#include "json.hpp"
+
+namespace json {
+
+template <class T>
+class Primitive : public Json
+{
+public:
+    Primitive() {}
+
+    Primitive(const T& value)
+        : value(value) {}
+
+    T get() const { return value; }
+    void set(T value) { this->value = value; }
+
+    operator T() const { return this->get(); }
+    
+protected:
+    T value;
+};
+
+
+}
+
+#endif
diff --git a/storage/json/real.hpp b/storage/json/real.hpp
new file mode 100644
index 000000000..214b2ba63
--- /dev/null
+++ b/storage/json/real.hpp
@@ -0,0 +1,33 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_REAL_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_REAL_HPP
+
+#include "primitive.hpp"
+
+namespace json {
+
+class Real final : public Primitive<float> 
+{
+public:
+    Real() {}
+
+    Real(float value)
+        : Primitive<float>(value) {}
+    
+    virtual bool is_real() const;
+
+    virtual operator std::string() const;
+};
+
+bool Real::is_real() const
+{
+    return true;
+}
+
+Real::operator std::string() const
+{
+    return std::to_string(value);
+}
+
+}
+
+#endif
diff --git a/storage/json/string.hpp b/storage/json/string.hpp
new file mode 100644
index 000000000..842a7399b
--- /dev/null
+++ b/storage/json/string.hpp
@@ -0,0 +1,34 @@
+#ifndef MEMGRAPH_DATA_MODEL_JSON_STRING_HPP
+#define MEMGRAPH_DATA_MODEL_JSON_STRING_HPP
+
+#include "primitive.hpp"
+
+namespace json
+{
+
+class String final : public Primitive<std::string>
+{
+public:
+    String() {}
+
+    String(const std::string& value) 
+        : Primitive<std::string>(value) {}
+
+    virtual bool is_string() const;
+
+    virtual operator std::string() const;
+};
+
+bool String::is_string() const
+{
+    return true;
+}
+
+String::operator std::string() const
+{
+    return "\"" + value + "\"";
+}
+
+}
+
+#endif
diff --git a/storage/record.hpp b/storage/record.hpp
new file mode 100644
index 000000000..fce83b192
--- /dev/null
+++ b/storage/record.hpp
@@ -0,0 +1,58 @@
+#ifndef MEMGRAPH_STORAGE_RECORD_HPP
+#define MEMGRAPH_STORAGE_RECORD_HPP
+
+#include <mutex>
+#include <list>
+
+#include "sync/spinlock.hpp"
+
+template <class lock_type = SpinLock>
+class Record
+{
+    // every node has a unique id. 2^64 = 1.8 x 10^19. that should be enough
+    // for a looong time :) but keep in mind that some vacuuming would be nice
+    // to reuse indices for deleted nodes. also, vacuuming would enable the
+    // use of uint32_t which could be more memory conserving
+    uint64_t id;
+
+    // acquire an exclusive guard on this node, use for concurrent access
+    std::unique_lock<lock_type> guard()
+    {
+        return std::unique_lock<lock_type>(lock);
+    }
+
+    uint64_t xmin()
+    {
+        return xmin_.load(std::memory_order_acquire);
+    }
+
+    uint64_t xmin_inc()
+    {
+        return xmin_.fetch_add(1, std::memory_order_relaxed);
+    }
+
+    uint64_t xmax()
+    {
+        return xmax_.load(std::memory_order_release);
+    }
+
+    uint64_t xmax_inc()
+    {
+        return xmax_.fetch_add(1, std::memory_order_relaxed);
+    }
+
+    Record* newer()
+    {
+        return versions.load(std::memory_order_consume);
+    }
+
+private:
+    // used by MVCC to keep track of what's visible to transactions
+    std::atomic<uint64_t> xmin_, xmax_;
+
+    std::atomic<Record*> versions;
+
+    lock_type lock;
+};
+
+#endif
diff --git a/storage/vertex.hpp b/storage/vertex.hpp
new file mode 100644
index 000000000..3c35e21d9
--- /dev/null
+++ b/storage/vertex.hpp
@@ -0,0 +1,14 @@
+#ifndef MEMGRAPH_STORAGE_VERTEX_HPP
+#define MEMGRAPH_STORAGE_VERTEX_HPP
+
+#include "record.hpp"
+#include "edge.hpp"
+
+struct Vertex : Record
+{
+    std::list<Edge*> out;
+
+    std::string name;
+};
+
+#endif