Neil Middleton

Sharing databases between Heroku applications

5 January, 2012

When you deploy an application to Heroku, you'll probably know that all applications receive a free 5mb database on their shared PostgreSQL database service. Whilst these are on shared servers at Heroku, the performance is still pretty good, and the cost of a size upgrade is cheap too ($15/mo for 20Gb).

However, sometimes we want our applications to share our data, and by default this isn't immediately obvious as to how this works.

Well, it's possible, but let's look into the background first.

Every Heroku application is able to have the shared-database:5mb add-on, and some deployments such as Rails, get it by default. Once this add-on is added to an application two things happen. Firstly, Heroku creates the database for you, and secondly, each time you deploy your application Heroku will overwrite your database configuration where possible (so for instance, with Rails, it will overwrite `config/database.yml' with their own version).

Essentially what this does it connects your application to an environment variable driven connection. You can see this by checking your configuration:

heroku config

This will yield a whole load of settings, but in amongst them you'll see something like:

DATABASE_URL => postgres://sakldjsad:kajshdsa@ec2-107-20-155-141.compute-1.amazonaws.com/sakldjsad

This is the database connection string that your application will be using.

So, how do we connect two applications together (or even replace the Heroku database with some other connection?)

Well, there's two ways. Firstly, you could simply overwrite the DATABASE_URL config variable:

heroku config:add DATABASE_URL=your_new_connection_string

an alternative is to use pg:promote which essentially does the same thing:

heroku pg:promote your_new_connection_string

By using this technique you can string your applications together in loads of different ways, sharing free databases, or even connecting lots of applications in a single Heroku Postgres instance.

For those Rails developers interested in how Heroku overwrites your config/database.yml, you can see the code below:

<%

require 'cgi'
require 'uri'

begin
  uri = URI.parse(ENV["DATABASE_URL"])
rescue URI::InvalidURIError
  raise "Invalid DATABASE_URL"
end

raise "No RACK_ENV or RAILS_ENV found" unless ENV["RAILS_ENV"] || ENV["RACK_ENV"]

def attribute(name, value)
  value ? "#{name}: #{value}" : ""
end

adapter = uri.scheme
adapter = "postgresql" if adapter == "postgres"

database = (uri.path || "").split("/")[1]

username = uri.user
password = uri.password

host = uri.host
port = uri.port

params = CGI.parse(uri.query || "")

%>

<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
  <%= attribute "adapter",  adapter %>
  <%= attribute "database", database %>
  <%= attribute "username", username %>
  <%= attribute "password", password %>
  <%= attribute "host",     host %>
  <%= attribute "port",     port %>

<% params.each do |key, value| %>
  <%= key %>: <%= value.first %>
<% end %>

I'm Neil Middleton.

I'm an engineer at Heroku based in the UK and the author of 'Heroku, Up & Running' for O'Reilly.

I'm a massive fan of keeping things simple, straight-forward and bullshit free.