4 min read

Learning to love bin/dev in Rails 7

Rails 7 introduced a new way to deal with assets via import maps and they also introduced a new way to run your app locally, the new bin/dev file. It’s not installed by default(yet) unless you create a new app with the -css option or it’s installed later on when you run the css:install command.

See also(video): Adding bin/dev to your pre Rails 7 application for a way to add bin/dev to any Rails app.

To get the new css/jss bundling configured with a new app you just need to specify what CSS framework you’d like to utilize if any, these options come from the cssbundling-rails gem.

$ rails new --help | grep css
-c, [—css=CSS]
# Choose CSS processor [options: tailwind, bootstrap, bulma, postcss, sass…

I’ll start a new app with rails new -c bootstrap which installs everything needed and creates the bin/dev file. If you’re looking to upgrade your app or install this in a new app just reference the full install options for the cssbundling-rails gem, it’s only two steps.

I really enjoy this approach because it’s another script to rule them all, we can now all align on one way to get things going locally. You run bin/setup and then you run bin/dev and your app should be running. If it isn’t running by that point, invest some time in making it so.

If you look at bin/dev you’ll see that it’s really simple and it’s just using the foreman gem along with a Procfile.dev. You’re most likely familiar with Procfile’s from Heroku or if you utilize them for your apps in various other hosting setups. Typically you’d just have a Procfile but Profile.dev is great to make it intentionally utilized for local development.

bin/dev runs as a bash script, installs foreman if it isn’t already installed and then starts foreman with the Procfile.dev as the Procfile.

#!/usr/bin/env bash

if ! command -v foreman &> /dev/null
  echo “Installing foreman…”
  gem install foreman

foreman start -f Procfile.dev “$@“

From here with the default setup your Procfile.dev only knows how to run a few processes(web, js, css). You can also easily modify this to say always boot the web process on a specific port, maybe you have a common authentication system for instance. We can also add a few additional processes like redis or postgresql, we’ll do that next.

web: bin/rails server -p 3000
js: yarn build —watch
css: yarn build:css —watch

With my local environment setup I boot up the backing services with docker compose, mainly the databases but really anything that’s more complicated than a brew install or where I might need multiple versions on my machine.

One service that I’m pretty much always using is Redis and it’s pretty trivial to get going with docker compose so lets add that and then update our bin/dev file.

I’m assuming you already have docker installed, if not follow your OS specific instructions to get that going before the next step.

Create a new docker-compose.yml file and add the redis service to it:

version: "3"
    image: redis:6.2.2-alpine
      - "6379:6379"

Now that we have this in place we can update our bin/dev file to boot this along with everything else.

redis: docker-compose up redis
web: bin/rails server -p 3000
js: yarn build --watch
css: yarn build:css --watch

Now when you run bin/dev you’ll see that it gets everything running that you need to start working on your application. You can see how you can easily add additional backing services or things that you’d like to run via docker compose or some other tool. Maybe you always want to run guard with live reload so that your changes automatically refresh in your browser.

And what if you already have redis running and you just need the one instance running? It’s really easy to disable booting a specific process with Foreman. If you didn’t notice, in the bin/dev script you’ll see “$@“ at the end of the foreman script which will pass the rest of the command arguments down to foreman.

To disable a specific process just set the process name to 0 when running bin/devbin/dev redis=0,all=1

This translates to, disable redis but run everything(all) else.

The Foreman manual has a few other options that are worth checking out too.

Provide some feedback on the Rails forum if this is something you’d find useful to be in there by default in the future.