Running modular Sinatra applications with foreman

It took me a bit of head scratching to figure out how to run a modular Sinatra app with foreman (as opposed to using a config.ru file). But I figured it out, so here’s an example:

require 'sinatra/base'
 
class MyApp < Sinatra::Base
  configure do
    set :app_file, __FILE__
    set :port, ENV['PORT']
  end
  
  get '/' do
    'hello world'
  end
 
  run! if app_file == $0
end

And here is the Procfile (assumes you’re using Bundler):

web: bundle exec ruby my_app.rb -p $PORT

The trick is that you need to set values for :app_file and :port. :app_file is needed because otherwise the script will just exit immediately without calling run!. This confused me a little because I thought it would be configured automatically.

Setting the value for port isn’t strictly necessary (it works locally and will start on the normal Sinatra port of 4567), but Heroku will kill your process if it doesn’t start on the right port. Foreman sets an environment variable called PORT that it wants to start the process on. Setting it in the configure block will make Sinatra use it.