diff --git a/lib/MetaCPAN/Web/Controller/Authors.pm b/lib/MetaCPAN/Web/Controller/Authors.pm
new file mode 100644
index 0000000000..40f8f9609c
--- /dev/null
+++ b/lib/MetaCPAN/Web/Controller/Authors.pm
@@ -0,0 +1,48 @@
+package MetaCPAN::Web::Controller::Authors;
+
+use Moose;
+use Data::Pageset;
+use List::Util ();
+use namespace::autoclean;
+
+BEGIN { extends 'MetaCPAN::Web::Controller' }
+
+sub index : Path : Args(0) {
+    my ( $self, $c ) = @_;
+
+    $c->stash( {
+        template => 'authors.html',
+    } );
+}
+
+sub authors : Path : Args(1) {
+    my ( $self, $c, $prefix ) = @_;
+
+    if ( $prefix ne uc $prefix ) {
+        $c->res->redirect(
+            $c->uri_for( $c->action, [ uc $prefix ], $c->req->params ),
+            301,    # Permanent
+        );
+        $c->detach;
+    }
+
+    my $page_size = $c->req->get_page_size(100);
+    my $page = $c->req->page > 0 ? $c->req->page : 1;
+
+    my $authors
+        = $c->model('API::Author')->by_prefix( $prefix, $page_size, $page )
+        ->get;
+
+    $c->stash($authors);
+    $c->stash( {
+        page      => $page,
+        page_size => $page_size,
+        prefix    => $prefix,
+    } );
+
+    $c->forward('index');
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/lib/MetaCPAN/Web/Model/API/Author.pm b/lib/MetaCPAN/Web/Model/API/Author.pm
index c19249edbe..8ded30c557 100644
--- a/lib/MetaCPAN/Web/Model/API/Author.pm
+++ b/lib/MetaCPAN/Web/Model/API/Author.pm
@@ -5,6 +5,7 @@ use namespace::autoclean;
 
 use Future ();
 use Ref::Util qw( is_arrayref );
+use URL::Encode qw(url_encode_utf8);
 
 extends 'MetaCPAN::Web::Model::API';
 
@@ -72,6 +73,27 @@ sub by_user {
     );
 }
 
+sub by_prefix {
+    my ( $self, $prefix, $page_size, $page ) = @_;
+
+    return Future->done( [] )
+        unless defined $prefix;
+
+    $page_size //= 100;
+    $page      //= 1;
+
+    my $from = $page_size * ( $page - 1 );
+
+    my $ret = $self->request(
+        '/author/by_prefix/' . url_encode_utf8($prefix),
+        undef,
+        {
+            from => $from,
+            size => $page_size,
+        }
+    );
+}
+
 __PACKAGE__->meta->make_immutable;
 
 1;
diff --git a/root/authors.html b/root/authors.html
new file mode 100644
index 0000000000..32ae5977a1
--- /dev/null
+++ b/root/authors.html
@@ -0,0 +1,13 @@
+<%- title = "CPAN Authors" %>
+
+<div class="content row">
+  <ul class="author-index">
+    <%- FOREACH letter IN [ 'A' .. 'Z' ] -%>
+<%    %><li<% IF letter == prefix; ' class="current"' | none; END %>><a href="/authors/<% letter %>"><% letter %></a></li><% -%>
+    <%- END %>
+  </ul>
+
+  <%- INCLUDE inc/author-grid.html %>
+
+  <%- INCLUDE inc/pager.html size = page_size %>
+</div>
diff --git a/root/inc/author-grid.html b/root/inc/author-grid.html
new file mode 100644
index 0000000000..d4270c772d
--- /dev/null
+++ b/root/inc/author-grid.html
@@ -0,0 +1,18 @@
+<div class="author-grid">
+<% FOREACH author IN authors %>
+<div class="entry col-sm-6 col-md-3">
+    <div class="gravatar">
+        <a href="/author/<% author.pauseid %>">
+            <img src="<% author.gravatar_image(75) %>" class="author-img" style="width: 75px; height: 75px">
+        </a>
+    </div>
+    <strong class="pauseid">
+        <a rel="author" href="/author/<% author.pauseid %>"><% author.pauseid %></a>
+    </strong>
+    <span class="name" title="<% author.asciiname %>"><% author.name %></span>
+    <%- IF author.releases.defined %>
+    <strong class="count"><% author.releases %> release<% IF author.releases > 1 %>s<% END %></strong>
+    <%- END %>
+</div>
+<% END %>
+</div>
diff --git a/root/recent/topuploaders.html b/root/recent/topuploaders.html
index 6b7de84a57..a2ae702f71 100644
--- a/root/recent/topuploaders.html
+++ b/root/recent/topuploaders.html
@@ -1,19 +1,6 @@
 <%- title = "CPAN Top Uploaders" %>
 <%- INCLUDE inc/recent-bar.html %>
 
-<div class="content toplists row">
-<% FOREACH author IN authors %>
-<div class="entry col-sm-6 col-md-3">
-    <div class="gravatar">
-        <a href="/author/<% author.pauseid %>">
-            <img src="<% author.gravatar_image(75) %>" class="author-img" style="width: 75px; height: 75px">
-        </a>
-    </div>
-    <strong class="pauseid">
-        <a rel="author" href="/author/<% author.pauseid %>"><% author.pauseid %></a>
-    </strong>
-    <span class="name" title="<% author.asciiname %>"><% author.name %></span>
-    <strong class="count"><% author.releases %> release<% IF author.releases > 1 %>s<% END %></strong>
-</div>
-<% END %>
+<div class="content row">
+  <%- INCLUDE inc/author-grid.html %>
 </div>
diff --git a/root/static/less/toplists.less b/root/static/less/author-grid.less
similarity index 96%
rename from root/static/less/toplists.less
rename to root/static/less/author-grid.less
index 9641e4d5f1..d7099c053b 100644
--- a/root/static/less/toplists.less
+++ b/root/static/less/author-grid.less
@@ -1,4 +1,4 @@
-.toplists {
+.author-grid {
     .entry {
         position: relative;
         float: left;
diff --git a/root/static/less/authors.less b/root/static/less/authors.less
new file mode 100644
index 0000000000..0bc449cfba
--- /dev/null
+++ b/root/static/less/authors.less
@@ -0,0 +1,31 @@
+.author-index {
+    text-align: center;
+    width: 100%;
+    li {
+        display: inline;
+
+        a {
+            display: inline-block;
+            text-align: center;
+            line-height: 28px;
+            width: 28px;
+            color: #fff;
+            background-color: @linkColor;
+            border: @linkColor 1px solid;
+            margin: 2px;
+        }
+
+        &.current {
+            a {
+                color: @linkColor;
+                background-color: #fff;
+            }
+        }
+
+        &:nth-child(13)::after {
+            display: block;
+            content: " ";
+        }
+    }
+    margin-bottom: 10px;
+}
diff --git a/root/static/less/style.less b/root/static/less/style.less
index cabec8fba7..7ffa4404b1 100644
--- a/root/static/less/style.less
+++ b/root/static/less/style.less
@@ -18,7 +18,8 @@
 @import "release.less";
 @import "search.less";
 @import "table.less";
-@import "toplists.less";
+@import "authors.less";
+@import "author-grid.less";
 @import "button.less";
 @import "nav.less";
 @import "nav-list.less";
