diff --git a/app/models/repository.rb b/app/models/repository.rb
index 8663cf5e602b2c30246102aa596e7c4de1824dfb..d27eeff9fb469192e6f0f78e0860a7aa7c0179f0 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -471,8 +471,17 @@ class Repository
   end
   cache_method :root_ref
 
+  # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314
   def exists?
-    refs_directory_exists?
+    return false unless path_with_namespace
+
+    Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
+      if enabled
+        raw_repository.exists?
+      else
+        refs_directory_exists?
+      end
+    end
   end
   cache_method :exists?
 
@@ -1095,8 +1104,6 @@ class Repository
   end
 
   def refs_directory_exists?
-    return false unless path_with_namespace
-
     File.exist?(File.join(path_to_repo, 'refs'))
   end
 
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 63eebadff2e94ca237f4edaa6b9ad05f74d96a77..3e27fd7b6826a3952b7380a9b7d7fea7201e62ee 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -45,6 +45,8 @@ module Gitlab
                 :bare?,
                 to: :rugged
 
+      delegate :exists?, to: :gitaly_repository_client
+
       # Default branch in the repository
       def root_ref
         @root_ref ||= gitaly_migrate(:root_ref) do |is_enabled|
@@ -208,10 +210,6 @@ module Gitlab
         !empty?
       end
 
-      def repo_exists?
-        !!rugged
-      end
-
       # Discovers the default branch based on the repository's available branches
       #
       # - If no branches are present, returns nil
@@ -815,6 +813,10 @@ module Gitlab
         @gitaly_commit_client ||= Gitlab::GitalyClient::CommitService.new(self)
       end
 
+      def gitaly_repository_client
+        @gitaly_repository_client ||= Gitlab::GitalyClient::RepositoryService.new(self)
+      end
+
       private
 
       # Gitaly note: JV: Trying to get rid of the 'filter' option so we can implement this with 'git'.
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 435e41e36fbdf748b6b027b79a1a8cb9eefc50a9..c90ef282fdd700fae966a22b5733156ff1da7b96 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -57,7 +57,7 @@ module Gitlab
       metadata = yield(metadata) if block_given?
       stub(service, storage).send(rpc, request, metadata)
     end
-  
+
     def self.request_metadata(storage)
       encoded_token = Base64.strict_encode64(token(storage).to_s)
       { metadata: { 'authorization' => "Bearer #{encoded_token}" } }
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f5d84ea8762c6666b4d7d2876ac42e0571ea7c5e
--- /dev/null
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -0,0 +1,16 @@
+module Gitlab
+  module GitalyClient
+    class RepositoryService
+      def initialize(repository)
+        @repository = repository
+        @gitaly_repo = repository.gitaly_repository
+      end
+
+      def exists?
+        request = Gitaly::RepositoryExistsRequest.new(repository: @gitaly_repo)
+
+        GitalyClient.call(@repository.storage, :repository_service, :exists, request).exists
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5a9f3fc130cb0ab762eafd7fc89493214d9b55ea
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::RepositoryService do
+  set(:project) { create(:empty_project) }
+  let(:storage_name) { project.repository_storage }
+  let(:relative_path) { project.path_with_namespace + '.git' }
+  let(:client) { described_class.new(project.repository) }
+
+  describe '#exists?' do
+    it 'sends an exists message' do
+      expect_any_instance_of(Gitaly::RepositoryService::Stub)
+        .to receive(:exists)
+        .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+        .and_call_original
+
+      client.exists?
+    end
+  end
+end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 7635b0868e7b4aaaf0dfd1d429891b57247e99b1..fcda42484465ae702d93f97a0c938ac1c267e749 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -956,21 +956,25 @@ describe Repository, models: true do
     end
   end
 
-  describe '#exists?' do
+  shared_examples 'repo exists check' do
     it 'returns true when a repository exists' do
       expect(repository.exists?).to eq(true)
     end
 
-    it 'returns false when a repository does not exist' do
-      allow(repository).to receive(:refs_directory_exists?).and_return(false)
+    it 'returns false if no full path can be constructed' do
+      allow(repository).to receive(:path_with_namespace).and_return(nil)
 
       expect(repository.exists?).to eq(false)
     end
+  end
 
-    it 'returns false when there is no namespace' do
-      allow(repository).to receive(:path_with_namespace).and_return(nil)
+  describe '#exists?' do
+    context 'when repository_exists is disabled' do
+      it_behaves_like 'repo exists check'
+    end
 
-      expect(repository.exists?).to eq(false)
+    context 'when repository_exists is enabled', skip_gitaly_mock: true do
+      it_behaves_like 'repo exists check'
     end
   end