diff --git a/api/funkwhale_api/federation/filters.py b/api/funkwhale_api/federation/filters.py
index 12cab7f892a555248a369635f452f84411755331..2803186baf036b6418d806a493adcb142af49d95 100644
--- a/api/funkwhale_api/federation/filters.py
+++ b/api/funkwhale_api/federation/filters.py
@@ -7,6 +7,9 @@ from . import models
 
 class LibraryFilter(django_filters.FilterSet):
     approved = django_filters.BooleanFilter('following__approved')
+    q = fields.SearchFilter(search_fields=[
+        'actor__domain',
+    ])
 
     class Meta:
         model = models.Library
diff --git a/front/src/components/Home.vue b/front/src/components/Home.vue
index 0e24dcd59008c52fe198e6a1778d9d1e0c00545c..ce1307ff0c8a84b934f027c7a27509644edc32a5 100644
--- a/front/src/components/Home.vue
+++ b/front/src/components/Home.vue
@@ -3,7 +3,7 @@
     <div class="ui vertical center aligned stripe segment">
       <div class="ui text container">
         <h1 class="ui huge header">
-            Welcome on Funkwhale
+          Welcome on Funkwhale
         </h1>
         <p>We think listening music should be simple.</p>
         <router-link class="ui icon button" to="/about">
diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue
index c04ebe5a866959c44dd74a8797d68f7b4f119e75..96047ab9848621c55fe5b75971bfca47e6c9ba62 100644
--- a/front/src/components/Sidebar.vue
+++ b/front/src/components/Sidebar.vue
@@ -47,7 +47,7 @@
           class="item" :to="{path: '/activity'}"><i class="bell icon"></i> Activity</router-link>
         <router-link
           class="item" v-if="$store.state.auth.availablePermissions['federation.manage']"
-          :to="{path: '/manage/federation'}"><i class="sitemap icon"></i> Federation</router-link>
+          :to="{path: '/manage/federation/libraries'}"><i class="sitemap icon"></i> Federation</router-link>
       </div>
 
       <player></player>
diff --git a/front/src/components/federation/LibraryCard.vue b/front/src/components/federation/LibraryCard.vue
index 9676f2de5ff03000e8e4490ca607f842953158b1..267d41bd0796bbe5e20c1f0d2bcc74ff745aa244 100644
--- a/front/src/components/federation/LibraryCard.vue
+++ b/front/src/components/federation/LibraryCard.vue
@@ -2,33 +2,39 @@
   <div class="ui card">
     <div class="content">
       <div class="header">
-        {{ libraryData.display_name }}
+        {{ displayName }}
       </div>
     </div>
     <div class="content">
-      <span class="right floated" v-if="libraryData.actor.manuallyApprovesFollowers">
+      <span class="right floated" v-if="following">
+        <i class="check icon"></i> Following
+      </span>
+      <span class="right floated" v-else-if="manuallyApprovesFollowers">
         <i class="lock icon"></i> Followers only
       </span>
+      <span class="right floated" v-else>
+        <i class="open lock icon"></i> Open
+      </span>
       <span>
         <i class="music icon"></i>
-        {{ libraryData.library.totalItems }} tracks
+        {{ totalItems }} tracks
       </span>
     </div>
     <div class="extra content">
-      <template v-if="libraryData.local.awaiting_approval">
+      <template v-if="awaitingApproval">
         <i class="clock icon"></i>
         Follow request pending approval
       </template>
-      <template v-else-if="libraryData.local.following">Pending follow request
+      <template v-else-if="following">
         <i class="check icon"></i>
         Already following this library
       </template>
       <div
-        v-else-if="!library"
+        v-if="!library"
         @click="follow"
         :disabled="isLoading"
         :class="['ui', 'basic', {loading: isLoading}, 'green', 'button']">
-        <template v-if="libraryData.actor.manuallyApprovesFollowers">
+        <template v-if="manuallyApprovesFollowers">
           Send a follow request
         </template>
         <template v-else>
@@ -49,13 +55,13 @@
 import axios from 'axios'
 
 export default {
-  props: ['libraryData'],
+  props: ['libraryData', 'libraryInstance'],
   data () {
     return {
+      library: this.libraryInstance,
       isLoading: false,
       data: null,
-      errors: [],
-      library: null
+      errors: []
     }
   },
   methods: {
@@ -77,6 +83,43 @@ export default {
         self.errors = error.backendErrors
       })
     }
+  },
+  computed: {
+    displayName () {
+      if (this.libraryData) {
+        return this.libraryData.display_name
+      } else {
+        return `${this.library.actor.preferred_username}@${this.library.actor.domain}`
+      }
+    },
+    manuallyApprovesFollowers () {
+      if (this.libraryData) {
+        return this.libraryData.actor.manuallyApprovesFollowers
+      } else {
+        return this.library.actor.manually_approves_followers
+      }
+    },
+    totalItems () {
+      if (this.libraryData) {
+        return this.libraryData.library.totalItems
+      } else {
+        return this.library.tracks_count
+      }
+    },
+    awaitingApproval () {
+      if (this.libraryData) {
+        return this.libraryData.local.awaiting_approval
+      } else {
+        return this.library.follow.approved === null
+      }
+    },
+    following () {
+      if (this.libraryData) {
+        return this.libraryData.local.following
+      } else {
+        return this.library.follow.approved
+      }
+    }
   }
 }
 </script>
diff --git a/front/src/router/index.js b/front/src/router/index.js
index 394a12849d6104c95e2427b9c31e05bc98992267..2b78375c1068233d801f2ac77b4da121f3f3fedc 100644
--- a/front/src/router/index.js
+++ b/front/src/router/index.js
@@ -26,8 +26,9 @@ import PlaylistDetail from '@/views/playlists/Detail'
 import PlaylistList from '@/views/playlists/List'
 import Favorites from '@/components/favorites/List'
 import FederationBase from '@/views/federation/Base'
-import FederationHome from '@/views/federation/Home'
+import FederationScan from '@/views/federation/Scan'
 import FederationLibraryDetail from '@/views/federation/LibraryDetail'
+import FederationLibraryList from '@/views/federation/LibraryList'
 
 Vue.use(Router)
 
@@ -90,15 +91,29 @@ export default new Router({
       path: '/manage/federation',
       component: FederationBase,
       children: [
-        { path: '', component: FederationHome },
-        { path: 'library/:id', name: 'federation.libraries.detail', component: FederationLibraryDetail, props: true }
+        {
+          path: 'scan',
+          name: 'federation.libraries.scan',
+          component: FederationScan },
+        {
+          path: 'libraries',
+          name: 'federation.libraries.list',
+          component: FederationLibraryList,
+          props: (route) => ({
+            defaultOrdering: route.query.ordering,
+            defaultQuery: route.query.query,
+            defaultPaginateBy: route.query.paginateBy,
+            defaultPage: route.query.page
+          })
+        },
+        { path: 'libraries/:id', name: 'federation.libraries.detail', component: FederationLibraryDetail, props: true }
       ]
     },
     {
       path: '/library',
       component: Library,
       children: [
-        { path: '', component: LibraryHome },
+        { path: 'scan', component: LibraryHome },
         {
           path: 'artists/',
           name: 'library.artists.browse',
diff --git a/front/src/views/federation/Base.vue b/front/src/views/federation/Base.vue
index 6add8e5e4c1eed00615bb4cd965c738d98e67d21..1919fd8556c61237d8c6301eb141740e951857ba 100644
--- a/front/src/views/federation/Base.vue
+++ b/front/src/views/federation/Base.vue
@@ -1,7 +1,23 @@
 <template>
   <div class="main pusher"  v-title="'Federation'">
     <div class="ui secondary pointing menu">
+      <router-link
+        class="ui item"
+        :to="{name: 'federation.libraries.list'}">Libraries</router-link>
     </div>
     <router-view :key="$route.fullPath"></router-view>
   </div>
 </template>
+<style lang="scss">
+@import '../../style/vendor/media';
+
+.main.pusher > .ui.secondary.menu {
+  @include media(">tablet") {
+    margin: 0 2.5rem;
+  }
+  .item {
+    padding-top: 1.5em;
+    padding-bottom: 1.5em;
+  }
+}
+</style>
diff --git a/front/src/views/federation/LibraryList.vue b/front/src/views/federation/LibraryList.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5c9d413a9cf66fb828900cf4c201ad0945b2c9c1
--- /dev/null
+++ b/front/src/views/federation/LibraryList.vue
@@ -0,0 +1,172 @@
+<template>
+  <div v-title="'Artists'">
+    <div class="ui vertical stripe segment">
+      <h2 class="ui header">Browsing libraries</h2>
+      <router-link
+        class="ui basic green button"
+        :to="{name: 'federation.libraries.scan'}">
+        <i class="plus icon"></i>
+        Add a new library
+      </router-link>
+      <div class="ui hidden divider"></div>
+      <div :class="['ui', {'loading': isLoading}, 'form']">
+        <div class="fields">
+          <div class="field">
+            <label>Search</label>
+            <input type="text" v-model="query" placeholder="Enter an library domain name..."/>
+          </div>
+          <div class="field">
+            <label>Ordering</label>
+            <select class="ui dropdown" v-model="ordering">
+              <option v-for="option in orderingOptions" :value="option[0]">
+                {{ option[1] }}
+              </option>
+            </select>
+          </div>
+          <div class="field">
+            <label>Ordering direction</label>
+            <select class="ui dropdown" v-model="orderingDirection">
+              <option value="">Ascending</option>
+              <option value="-">Descending</option>
+            </select>
+          </div>
+          <div class="field">
+            <label>Results per page</label>
+            <select class="ui dropdown" v-model="paginateBy">
+              <option :value="parseInt(12)">12</option>
+              <option :value="parseInt(25)">25</option>
+              <option :value="parseInt(50)">50</option>
+            </select>
+          </div>
+        </div>
+      </div>
+      <div class="ui hidden divider"></div>
+      <div
+        v-if="result"
+        v-masonry
+        transition-duration="0"
+        item-selector=".column"
+        percent-position="true"
+        stagger="0"
+        class="ui stackable three column doubling grid">
+        <div
+          v-masonry-tile
+          v-if="result.results.length > 0"
+          v-for="library in result.results"
+          :key="library.id"
+          class="column">
+          <library-card class="fluid" :library-instance="library"></library-card>
+        </div>
+      </div>
+      <div class="ui center aligned basic segment">
+        <pagination
+          v-if="result && result.results.length > 0"
+          @page-changed="selectPage"
+          :current="page"
+          :paginate-by="paginateBy"
+          :total="result.count"
+          ></pagination>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import axios from 'axios'
+import _ from 'lodash'
+import $ from 'jquery'
+
+import logger from '@/logging'
+
+import OrderingMixin from '@/components/mixins/Ordering'
+import PaginationMixin from '@/components/mixins/Pagination'
+import LibraryCard from '@/components/federation/LibraryCard'
+import Pagination from '@/components/Pagination'
+
+const FETCH_URL = 'federation/libraries/'
+
+export default {
+  mixins: [OrderingMixin, PaginationMixin],
+  props: {
+    defaultQuery: {type: String, required: false, default: ''}
+  },
+  components: {
+    LibraryCard,
+    Pagination
+  },
+  data () {
+    let defaultOrdering = this.getOrderingFromString(this.defaultOrdering || '-creation_date')
+    return {
+      isLoading: true,
+      result: null,
+      page: parseInt(this.defaultPage),
+      query: this.defaultQuery,
+      paginateBy: parseInt(this.defaultPaginateBy || 50),
+      orderingDirection: defaultOrdering.direction,
+      ordering: defaultOrdering.field,
+      orderingOptions: [
+        ['creation_date', 'Creation date'],
+        ['tracks_count', 'Available tracks']
+      ]
+    }
+  },
+  created () {
+    this.fetchData()
+  },
+  mounted () {
+    $('.ui.dropdown').dropdown()
+  },
+  methods: {
+    updateQueryString: _.debounce(function () {
+      this.$router.replace({
+        query: {
+          query: this.query,
+          page: this.page,
+          paginateBy: this.paginateBy,
+          ordering: this.getOrderingAsString()
+        }
+      })
+    }, 500),
+    fetchData: _.debounce(function () {
+      var self = this
+      this.isLoading = true
+      let url = FETCH_URL
+      let params = {
+        page: this.page,
+        q: this.query,
+        ordering: this.getOrderingAsString()
+      }
+      logger.default.debug('Fetching libraries')
+      axios.get(url, {params: params}).then((response) => {
+        self.result = response.data
+        self.isLoading = false
+      })
+    }, 500),
+    selectPage: function (page) {
+      this.page = page
+    }
+  },
+  watch: {
+    page () {
+      this.updateQueryString()
+      this.fetchData()
+    },
+    ordering () {
+      this.updateQueryString()
+      this.fetchData()
+    },
+    orderingDirection () {
+      this.updateQueryString()
+      this.fetchData()
+    },
+    query () {
+      this.updateQueryString()
+      this.fetchData()
+    }
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+</style>
diff --git a/front/src/views/federation/Home.vue b/front/src/views/federation/Scan.vue
similarity index 94%
rename from front/src/views/federation/Home.vue
rename to front/src/views/federation/Scan.vue
index 89048aac58299e140f88c87807e19e9f9b1733ba..5caa2f5405b43a4194e9571edd22c2277a9adc36 100644
--- a/front/src/views/federation/Home.vue
+++ b/front/src/views/federation/Scan.vue
@@ -1,7 +1,6 @@
 <template>
   <div>
     <div class="ui vertical stripe segment">
-      <h1 class="ui header">Manage federation</h1>
       <library-form @scanned="updateLibraryData"></library-form>
       <library-card v-if="libraryData" :library-data="libraryData"></library-card>
     </div>