diff --git a/app/main/routes.py b/app/main/routes.py
index 7e42d60b62b8afdf4dc26f73aa84bb8cf7922a40..fd01e5a6d7abbf846147a776e5a38b24f0770dd9 100644
--- a/app/main/routes.py
+++ b/app/main/routes.py
@@ -1,5 +1,5 @@
 from flask import flash, redirect, render_template, url_for
-from flask_login import login_required, login_user
+from flask_login import current_user, login_required, login_user
 from app.auth.forms import LoginForm
 from app.models import User
 from . import bp
@@ -27,7 +27,11 @@ def faq():
 @bp.route('/dashboard')
 @login_required
 def dashboard():
-    return render_template('main/dashboard.html.j2', title='Dashboard')
+    users = [
+        u.to_json_serializeable(filter_by_privacy_settings=True, include_avatar_relationship=True) for u
+        in User.query.filter(User.is_public == True, User.id != current_user.id).all()
+    ]
+    return render_template('main/dashboard.html.j2', title='Dashboard', users=users)
 
 
 @bp.route('/dashboard2')
diff --git a/app/models.py b/app/models.py
index aa5b2faa720001837b130f2c89162813808df8a3..afa0e40c6ba5de14758965298c3c970646557e4c 100644
--- a/app/models.py
+++ b/app/models.py
@@ -256,8 +256,7 @@ class Avatar(HashidMixin, FileMixin, db.Model):
     # Primary key
     id = db.Column(db.Integer, primary_key=True)
     # Foreign keys
-    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
-    # Backrefs: user: User
+    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), unique=True)
     
     @property
     def path(self):
@@ -270,7 +269,12 @@ class Avatar(HashidMixin, FileMixin, db.Model):
             current_app.logger.error(e)
         db.session.delete(self)
 
-
+    def to_json_serializeable(self, backrefs=False, relationships=False):
+        json_serializeable = {
+            'id': self.id
+        }
+        return json_serializeable
+    
 class User(HashidMixin, UserMixin, db.Model):
     __tablename__ = 'users'
     # Primary key
@@ -536,7 +540,16 @@ class User(HashidMixin, UserMixin, db.Model):
         self.profile_privacy_settings = 0
     #endregion Profile Privacy settings
 
-    def to_json_serializeable(self, backrefs=False, relationships=False):
+    def to_json_serializeable(
+        self, backrefs=False, 
+        relationships=False, 
+        filter_by_privacy_settings=False,
+        include_corpus_relationships=False,
+        include_job_relationships=False,
+        include_tesseract_ocr_pipeline_model_relationships=False,
+        include_spacy_nlp_pipeline_model_relationships=False,
+        include_avatar_relationship=False
+    ):
         json_serializeable = {
             'id': self.hashid,
             'confirmed': self.confirmed,
@@ -562,23 +575,39 @@ class User(HashidMixin, UserMixin, db.Model):
         if backrefs:
             json_serializeable['role'] = \
                 self.role.to_json_serializeable(backrefs=True)
-        if relationships:
+        if relationships or include_corpus_relationships:
             json_serializeable['corpora'] = {
                 x.hashid: x.to_json_serializeable(relationships=True)
                 for x in self.corpora
             }
+        if relationships or include_job_relationships:
             json_serializeable['jobs'] = {
                 x.hashid: x.to_json_serializeable(relationships=True)
                 for x in self.jobs
             }
+        if relationships or include_tesseract_ocr_pipeline_model_relationships:
             json_serializeable['tesseract_ocr_pipeline_models'] = {
                 x.hashid: x.to_json_serializeable(relationships=True)
                 for x in self.tesseract_ocr_pipeline_models
             }
+        if relationships or include_spacy_nlp_pipeline_model_relationships:
             json_serializeable['spacy_nlp_pipeline_models'] = {
                 x.hashid: x.to_json_serializeable(relationships=True)
                 for x in self.spacy_nlp_pipeline_models
             }
+        if relationships or include_avatar_relationship:
+            json_serializeable['avatar'] = (
+                None if self.avatar is None
+                else self.avatar.to_json_serializeable(relationships=True)
+            )
+
+        if filter_by_privacy_settings:
+            if not self.has_profile_privacy_setting(ProfilePrivacySettings.SHOW_EMAIL):
+                json_serializeable.pop('email')
+            if not self.has_profile_privacy_setting(ProfilePrivacySettings.SHOW_LAST_SEEN):
+                json_serializeable.pop('last_seen')
+            if not self.has_profile_privacy_setting(ProfilePrivacySettings.SHOW_MEMBER_SINCE):
+                json_serializeable.pop('member_since')
         return json_serializeable
 
 
diff --git a/app/profile/routes.py b/app/profile/routes.py
index b4711aa54c8113066150d738a9502f4995005232..8c1f8e81cbce8c994006305b12817a4e69fd7f92 100644
--- a/app/profile/routes.py
+++ b/app/profile/routes.py
@@ -54,7 +54,6 @@ def delete_avatar(avatar_id, user_id):
     def _delete_avatar(app, avatar_id):
         with app.app_context():
             avatar_file = Avatar.query.get(avatar_id)
-            print(avatar_file)
             avatar_file.delete()
             db.session.commit()
     thread = Thread(
diff --git a/app/static/js/RessourceLists/PublicUserList.js b/app/static/js/RessourceLists/PublicUserList.js
new file mode 100644
index 0000000000000000000000000000000000000000..4597ed3e2b97b410a5fdd372190b17795343e82f
--- /dev/null
+++ b/app/static/js/RessourceLists/PublicUserList.js
@@ -0,0 +1,79 @@
+class PublicUserList extends RessourceList {
+  static autoInit() {
+    for (let publicUserListElement of document.querySelectorAll('.public-user-list:not(.no-autoinit)')) {
+      new PublicUserList(publicUserListElement);
+    }
+  }
+
+  static options = {
+    initialHtmlGenerator: (id) => {
+      console.log(id);
+      return `
+        <div class="input-field">
+          <i class="material-icons prefix">search</i>
+          <input id="${id}-search" class="search" type="search"></input>
+          <label for="${id}-search">Search user</label>
+        </div>
+        <table>
+          <thead>
+            <tr>
+              <th style="width:15%;"></th>
+              <th>Username</th>
+              <th></th>
+            </tr>
+          </thead>
+          <tbody class="list"></tbody>
+        </table>
+        <ul class="pagination"></ul>
+      `.trim();
+    },
+    item: `
+      <tr class="clickable hoverable">
+        <td><img alt="user-image" class="circle responsive-img avatar" style="width:80%"></td>
+        <td><span class="username"></span></td>
+        <td class="right-align">
+          <a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a>
+        </td>
+      </tr>
+    `.trim(),
+    ressourceMapper: (user) => {
+      return {
+        'id': user.id,
+        'member-since': user.member_since,
+        'avatar': `/static/images/user_avatar.png`,
+        'username': user.username
+      };
+    },
+    sortArgs: ['member-since', {order: 'desc'}],
+    valueNames: [
+      {data: ['id']},
+      {data: ['member-since']},
+      {name: 'avatar', attr: 'src'},
+      'username'
+    ]
+  };
+
+  constructor(listElement, options = {}) {
+    super(listElement, {...PublicUserList.options, ...options});
+  }
+
+  init(users) {
+    super._init(Object.values(users));
+  }
+
+  onClick(event) {
+    let actionButtonElement = event.target.closest('.action-button');
+    let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
+    let publicUserElement = event.target.closest('tr');
+    let publicUserId = publicUserElement.dataset.id;
+    switch (action) {
+      case 'view': {
+        window.location.href = `/profile/${publicUserId}`;
+        break;
+      }
+      default: {
+        break;
+      }
+    }
+  }
+}
diff --git a/app/static/js/RessourceLists/RessourceList.js b/app/static/js/RessourceLists/RessourceList.js
index 323f9d0e7b455e83fb04a43da03d919fecda6462..e53367fd2eb4021ea92329dc4a71d30326409703 100644
--- a/app/static/js/RessourceLists/RessourceList.js
+++ b/app/static/js/RessourceLists/RessourceList.js
@@ -10,6 +10,8 @@ class RessourceList {
     JobList.autoInit();
     JobInputList.autoInit();
     JobResultList.autoInit();
+    PublicCorporaList.autoInit();
+    PublicUserList.autoInit();
     SpaCyNLPPipelineModelList.autoInit();
     TesseractOCRPipelineModelList.autoInit();
     UserList.autoInit();
diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index 24d24d974bc7877efa90c7670149afa29498179b..84b03e6261cf112fe5f8fa1ab52d627829ca377e 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -24,6 +24,8 @@
   'js/RessourceLists/JobList.js',
   'js/RessourceLists/JobInputList.js',
   'js/RessourceLists/JobResultList.js',
+  'js/RessourceLists/PublicCorporaList.js',
+  'js/RessourceLists/PublicUserList.js',
   'js/RessourceLists/SpacyNLPPipelineModelList.js',
   'js/RessourceLists/TesseractOCRPipelineModelList.js',
   'js/RessourceLists/UserList.js',
diff --git a/app/templates/admin/users.html.j2 b/app/templates/admin/users.html.j2
index 75254b0e45a7eac5e6a65264ce4a51b5c36b2a10..55c5dc2d8d77451d3c94528aaacca5933acffbac 100644
--- a/app/templates/admin/users.html.j2
+++ b/app/templates/admin/users.html.j2
@@ -22,11 +22,7 @@
 {% block scripts %}
 {{ super() }}
 <script>
-  for (let user of {{ json_users|tojson }}) {
-    if (user.id in app.data.users) {continue;}
-    app.data.users[user.id] = user;
-  }
   let userList = new UserList(document.querySelector('.user-list'));
-  userList.init(app.data.users);
+  userList._init({{ json_users|tojson }});
 </script>
 {% endblock scripts %}
diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2
index e0354ea624eff3230e0a2d392fb2d6a93ca4ba45..eb504cb3b2082cc56ba0853d380f1ea43043a9e5 100644
--- a/app/templates/main/dashboard.html.j2
+++ b/app/templates/main/dashboard.html.j2
@@ -49,6 +49,7 @@
           <div class="card-content">
             <span class="card-title">Other users and groups</span>
             <p>Find other users and follow them to see their corpora and groups.</p>
+            <div class="public-user-list no-autoinit"></div>
           </div>
         </div>
       </div>
@@ -115,3 +116,11 @@
   </div>
 </div>
 {% endblock modals %}
+
+{% block scripts %}
+{{ super() }}
+<script>
+  let publicUserList = new PublicUserList(document.querySelector('.public-user-list'));
+  publicUserList._init({{ users|tojson }});
+</script>
+{% endblock scripts %}