diff --git a/app/controllers/aspects_controller.rb b/app/controllers/aspects_controller.rb
index 2f4317195cc3ec320ee799065e4991b68451738d..ec8af115dc7acf7e21e521f885a7f34e713cefc4 100644
--- a/app/controllers/aspects_controller.rb
+++ b/app/controllers/aspects_controller.rb
@@ -38,7 +38,7 @@ class AspectsController < ApplicationController
                                            :type => ['StatusMessage','ActivityStreams::Photo'],
                                            :order => session[:sort_order] + ' DESC',
                                            :max_time => params[:max_time].to_i
-                          ).includes(:likes, {:comments => {:author => :profile}}, {:mentions => {:person => :profile}})
+                          ).includes({:comments => {:author => :profile}}, {:mentions => {:person => :profile}})
 
     @posts = PostsFake.new(posts)
     if params[:only_posts]
diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb
index b008dc41a7fc5460d6847f096c8a77aba401ff4f..696a0ba3c2c08731880a1942a11052d2f9d51586 100644
--- a/app/controllers/likes_controller.rb
+++ b/app/controllers/likes_controller.rb
@@ -9,7 +9,7 @@ class LikesController < ApplicationController
   respond_to :html, :mobile, :json
 
   def create
-    target = current_user.find_visible_post_by_id params[:post_id]
+    target = current_user.find_visible_post_by_id params[:status_message_id]
     positive = (params[:positive] == 'true') ? true : false
     if target
       @like = current_user.build_like(:positive => positive, :post => target)
@@ -32,7 +32,7 @@ class LikesController < ApplicationController
   end
 
   def destroy
-    if @like = Like.where(:id => params[:id], :author_id => current_user.person.id).first
+    if @like = Like.where(:id => params[:id], :author_id => current_user.person.id, :post_id => params[:status_message_id]).first
       current_user.retract(@like)
     else
       respond_to do |format|
@@ -41,4 +41,13 @@ class LikesController < ApplicationController
       end
     end
   end
+
+  def index
+    if target = current_user.find_visible_post_by_id(params[:status_message_id])
+      @likes = target.likes.includes(:author => :profile)
+      render :layout => false
+    else
+      render :nothing => true, :status => 404
+    end
+  end
 end
diff --git a/app/helpers/likes_helper.rb b/app/helpers/likes_helper.rb
index c9f9b3801675f4229af2bcd70e42b6af7579f69b..0648bed4e465876c11d1793101f662855b5d1094 100644
--- a/app/helpers/likes_helper.rb
+++ b/app/helpers/likes_helper.rb
@@ -10,9 +10,9 @@ module LikesHelper
 
   def like_action(post, current_user=current_user)
     if current_user.liked?(post)
-      link_to t('shared.stream_element.unlike'), like_path(current_user.like_for(post)), :method => :delete, :class => 'unlike', :remote => true
+      link_to t('shared.stream_element.unlike'), status_message_like_path(post, current_user.like_for(post)), :method => :delete, :class => 'unlike', :remote => true
     else
-      link_to t('shared.stream_element.like'), likes_path(:positive => 'true', :post_id => post.id ), :method => :post, :class => 'like', :remote => true
+      link_to t('shared.stream_element.like'), status_message_likes_path(post, :positive => 'true'), :method => :post, :class => 'like', :remote => true
     end
   end
 end
diff --git a/app/models/like.rb b/app/models/like.rb
index 156775e445f1ebb8a02874dece00cd1b460f73f4..9d549e909d0911b338a2589e5c8728c46449de13 100644
--- a/app/models/like.rb
+++ b/app/models/like.rb
@@ -15,7 +15,7 @@ class Like < ActiveRecord::Base
   xml_attr :positive
   xml_attr :diaspora_handle
 
-  belongs_to :post
+  belongs_to :post, :counter_cache => true
   belongs_to :author, :class_name => 'Person'
 
   validates_uniqueness_of :post_id, :scope => :author_id
diff --git a/app/models/user.rb b/app/models/user.rb
index 9a2173f8d3d1fa63be46b094be23a5a3e866bfbd..0bab1c58ead984b722c606128cdeafe22a2242e3 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -182,10 +182,14 @@ class User < ActiveRecord::Base
   # Check whether the user has liked a post.  Extremely inefficient if the post's likes are not loaded.
   # @param [Post] post
   def liked?(post)
-    if self.like_for(post)
-      return true
+    if post.likes.loaded?
+      if self.like_for(post)
+        return true
+      else
+        return false
+      end
     else
-      return false
+      Like.exists?(:author_id => self.person.id, :post_id => post.id)
     end
   end
 
@@ -193,10 +197,11 @@ class User < ActiveRecord::Base
   # @param [Post] post
   # @return [Like]
   def like_for(post)
-    post.likes.each do |like|
-      return like if like.author_id == self.person.id
+    if post.likes.loaded?
+      return post.likes.detect{ |like| like.author_id == self.person.id }
+    else
+      return Like.where(:author_id => self.person.id, :post_id => post.id).first
     end
-    return nil
   end
 
   ######### Mailer #######################
diff --git a/app/views/likes/_likes.haml b/app/views/likes/_likes.haml
index 2d0bd5faeaffcf24a3d5b3502a2daee2078f0d87..6536917c00da9bfa083071b815c6fe2329abd8bc 100644
--- a/app/views/likes/_likes.haml
+++ b/app/views/likes/_likes.haml
@@ -2,11 +2,5 @@
 -#   licensed under the Affero General Public License version 3 or later.  See
 -#   the COPYRIGHT file.
 
-- if likes.size > 0
-  .likes_container
-    .likes
-      = image_tag('icons/heart.svg')
-      = link_to t('.people_like_this', :count => likes.length), "#", :class => "expand_likes"
-      %span.hidden.likes_list
-        = notification_people_link(nil, likes.map{|x| x.author})
+= notification_people_link(nil, likes.map{|x| x.author})
 
diff --git a/app/views/likes/_likes_container.haml b/app/views/likes/_likes_container.haml
new file mode 100644
index 0000000000000000000000000000000000000000..eb39d2136b6b17dd0d8aa070cdc8210507c1f625
--- /dev/null
+++ b/app/views/likes/_likes_container.haml
@@ -0,0 +1,12 @@
+-#   Copyright (c) 2010, Diaspora Inc.  This file is
+-#   licensed under the Affero General Public License version 3 or later.  See
+-#   the COPYRIGHT file.
+
+- if likes_count > 0
+  .likes_container
+    .likes
+      = image_tag('icons/heart.svg')
+      = link_to t('likes.likes.people_like_this', :count => likes_count), status_message_likes_path(post_id), :class => "expand_likes"
+      %span.hidden.likes_list
+        /= render 'likes/likes', :likes => likes
+
diff --git a/app/views/likes/create.js.erb b/app/views/likes/create.js.erb
index 67b90b85d064a38f147354b024664116c31d789f..ff6f0ef63c30a3fa94b6a41e94c45f73751eb6e6 100644
--- a/app/views/likes/create.js.erb
+++ b/app/views/likes/create.js.erb
@@ -1,4 +1,4 @@
 $(".like_action", ".stream_element[data-guid=<%=@like.post_id%>]").html("<%= escape_javascript(like_action(@like.post))%>");
 
-WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes", :post_id => @like.post_id, :likes => @like.post.likes)) %>");
+WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes_container", :post_id => @like.post_id, :likes_count => @like.post.likes.count)) %>");
 
diff --git a/app/views/likes/destroy.js.erb b/app/views/likes/destroy.js.erb
index 2c9e5e9a4d5115f25e11438bba0470f47acc64ae..0f96633482d80303463fd38161ec318f980b35dd 100644
--- a/app/views/likes/destroy.js.erb
+++ b/app/views/likes/destroy.js.erb
@@ -1,3 +1,3 @@
 $(".like_action", ".stream_element[data-guid=<%=@like.post_id%>]").html("<%= escape_javascript(like_action(@like.post))%>");
-WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes", :post_id => @like.post_id, :likes => @like.post.likes)) %>");
+WebSocketReceiver.processLike("<%=@like.post_id%>", "<%= escape_javascript(render("likes/likes_container", :post_id => @like.post_id, :likes_count => @like.post.likes.count)) %>");
 
diff --git a/app/views/likes/index.html.haml b/app/views/likes/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..3fe13daaaca4e2d8f297350bcac578c01ab280ef
--- /dev/null
+++ b/app/views/likes/index.html.haml
@@ -0,0 +1 @@
+= render 'likes', :likes => @likes
diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml
index 8fb5000b38eb7fe65b9971dc8c49995e22dc8a29..dfc4d5dba943ae38820c2dfbd4c6ceff738a05c2 100644
--- a/app/views/photos/show.html.haml
+++ b/app/views/photos/show.html.haml
@@ -65,5 +65,5 @@
   #photo_stream.stream.show
     %div{:data=>{:guid=>parent.id}}
       .likes_container
-        = render "likes/likes", :post_id => parent.id, :likes => parent.likes
+        = render "likes/likes_container", :post_id => parent.id, :likes_count => parent.likes_count
       = render "comments/comments", :post => parent, :comments => parent.comments, :always_expanded => true
diff --git a/app/views/shared/_stream_element.html.haml b/app/views/shared/_stream_element.html.haml
index 82e70877870c726c8bf813baeee6d10edeb21641..acf88cc8d9adc3a54ee133292e1eb9f4585618b7 100644
--- a/app/views/shared/_stream_element.html.haml
+++ b/app/views/shared/_stream_element.html.haml
@@ -51,7 +51,7 @@
           = link_to t('comments.new_comment.comment'), '#', :class => 'focus_comment_textarea'
 
       .likes
-        - if post.likes.size > 0
-          = render "likes/likes", :post_id => post.id, :likes => post.likes, :current_user => current_user
+        - if post.likes_count > 0
+          = render "likes/likes_container", :post_id => post.id, :likes_count => post.likes_count, :current_user => current_user
 
       = render "comments/comments", :post => post, :comments => post.comments, :current_user => current_user, :condensed => true, :commenting_disabled => (defined?(@commenting_disabled) && @commenting_disabled)
diff --git a/config/routes.rb b/config/routes.rb
index d3895c5b964c3777480b918aa19c467f9998fb62..7627953bd2c6e59aceb8cee9e2deb9ea90ccfdd1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -10,7 +10,10 @@ Diaspora::Application.routes.draw do
     put 'toggle_contact_visibility' => :toggle_contact_visibility
   end
 
-  resources :status_messages, :only => [:new, :create, :destroy, :show]
+  resources :status_messages, :only => [:new, :create, :destroy, :show] do
+    resources :likes, :only => [:create, :destroy, :index]
+  end
+
   get 'bookmarklet' => 'status_messages#bookmarklet'
   get 'p/:id'       => 'posts#show', :as => 'post'
 
@@ -20,7 +23,6 @@ Diaspora::Application.routes.draw do
 
   resources :comments, :only => [:create, :destroy]
 
-  resources :likes, :only => [:create, :destroy]
 
   resources :conversations do
     resources :messages, :only => [:create, :show]
diff --git a/db/migrate/20110705003445_counter_cache_on_post_likes.rb b/db/migrate/20110705003445_counter_cache_on_post_likes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2d4f55f4cdb8086f1a0fb28894c402c86f84dca4
--- /dev/null
+++ b/db/migrate/20110705003445_counter_cache_on_post_likes.rb
@@ -0,0 +1,9 @@
+class CounterCacheOnPostLikes < ActiveRecord::Migration
+  def self.up
+    add_column :posts, :likes_count, :integer, :default => 0
+  end
+
+  def self.down
+    remove_column :posts, :likes_count
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 86ba0bfe074413b656e16e8c1131ba72031f2c9d..085facef9ece0468a2ed1ce00e842f70ab749b92 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20110623210918) do
+ActiveRecord::Schema.define(:version => 20110705003445) do
 
   create_table "aspect_memberships", :force => true do |t|
     t.integer  "aspect_id",  :null => false
@@ -266,6 +266,7 @@ ActiveRecord::Schema.define(:version => 20110623210918) do
     t.string   "actor_url"
     t.integer  "objectId"
     t.string   "status_message_guid"
+    t.integer  "likes_count",                         :default => 0
   end
 
   add_index "posts", ["author_id"], :name => "index_posts_on_person_id"
diff --git a/public/javascripts/widgets/post.js b/public/javascripts/widgets/post.js
index 79bd975c89822c3f3d2fcdccf09d9dfcc6fb312f..14bd300fb84c8d4c958dc89d203fec59ea79c9f5 100644
--- a/public/javascripts/widgets/post.js
+++ b/public/javascripts/widgets/post.js
@@ -20,11 +20,7 @@
     };
 
     this.setUpLikes = function() {
-      $(this.expandLikesSelector).live("click", function(evt) {
-        evt.preventDefault();
-        $(this).siblings(".likes_list")
-          .fadeToggle("fast");
-      });
+      $(this.expandLikesSelector).live("click", this.expandLikes);
 
       var likeIt = $(this.likesSelector);
 
@@ -37,7 +33,24 @@
         $(this).parent().fadeIn("fast");
       });
     };
+    this.expandLikes = function(evt){
+      evt.preventDefault();
+      var likesList = $(this).siblings(".likes_list");
+      if(likesList.children().length == 0){
+        likesList.append("<img alt='loading' src='/images/ajax-loader.gif' />");
+        $.ajax({
+          url: this.href,
+          success: function(data){
+            likesList.html(data);
+            likesList.fadeToggle("fast");
+          }
+        });
+      }else {
+      likesList
+        .fadeToggle("fast");
+      }
+    };
   };
 
   Diaspora.widgets.add("post", Post);
-})();
\ No newline at end of file
+})();
diff --git a/spec/controllers/likes_controller_spec.rb b/spec/controllers/likes_controller_spec.rb
index 8ec331a085feb946b6f3aada2ea66c54385dcb30..b5e37fb42d5d62542722d1cf6902ed470b9f6d7e 100644
--- a/spec/controllers/likes_controller_spec.rb
+++ b/spec/controllers/likes_controller_spec.rb
@@ -12,18 +12,17 @@ describe LikesController do
     @aspect1 = @user1.aspects.first
     @aspect2 = @user2.aspects.first
 
-    @controller.stub(:current_user).and_return(alice)
     sign_in :user, @user1
   end
 
   describe '#create' do
     let(:like_hash) {
       {:positive => 1,
-       :post_id => "#{@post.id}"}
+       :status_message_id => "#{@post.id}"}
     }
     let(:dislike_hash) {
       {:positive => 0,
-       :post_id => "#{@post.id}"}
+       :status_message_id => "#{@post.id}"}
     }
 
     context "on my own post" do
@@ -72,6 +71,29 @@ describe LikesController do
     end
   end
 
+  describe '#index' do
+    before do
+      @message = alice.post(:status_message, :text => "hey", :to => @aspect1.id)
+    end
+    it 'returns a 404 for a post not visible to the user' do
+      sign_in eve
+      get :index, :status_message_id => @message.id
+    end
+
+    it 'returns an array of likes for a post' do
+      like = bob.build_like(:positive => true, :post => @message)
+      like.save!
+
+      get :index, :status_message_id => @message.id
+      assigns[:likes].map(&:id).should == @message.likes.map(&:id)
+    end
+
+    it 'returns an empty array for a post with no likes' do
+      get :index, :status_message_id => @message.id
+      assigns[:likes].should == []
+    end
+  end
+
   describe '#destroy' do
     before do
       @message = bob.post(:status_message, :text => "hey", :to => @aspect1.id)
@@ -81,7 +103,7 @@ describe LikesController do
 
     it 'lets a user destroy their like' do
       expect {
-        delete :destroy, :format => "js", :post_id => @like.post_id, :id => @like.id
+        delete :destroy, :format => "js", :status_message_id => @like.post_id, :id => @like.id
       }.should change(Like, :count).by(-1)
       response.status.should == 200
     end
@@ -91,7 +113,7 @@ describe LikesController do
       like2.save
 
       expect {
-        delete :destroy, :format => "js", :post_id => like2.post_id, :id => like2.id
+        delete :destroy, :format => "js", :status_message_id => like2.post_id, :id => like2.id
       }.should_not change(Like, :count)
 
       response.status.should == 403
diff --git a/spec/models/like_spec.rb b/spec/models/like_spec.rb
index 19c0b496319b8a403a3081b728c7d7580029308e..ade64c299960ac7489585a9d25257e6de27114b2 100644
--- a/spec/models/like_spec.rb
+++ b/spec/models/like_spec.rb
@@ -56,6 +56,14 @@ describe Like do
     end
   end
 
+  describe 'counter cache' do
+    it 'increments the counter cache on its post' do
+      lambda {
+        @alice.like(1, :post => @status)
+      }.should change{ @status.reload.likes_count }.by(1)
+    end
+  end
+
   describe 'xml' do
     before do
       @liker = Factory.create(:user)