Starting Rails 7 for Front-End Development

Richard Gonsales
December 21, 2022

Rails 7 is now more flexible in terms of the front-end technologies we want to use for our projects. Webpacker has been retired and right now is not really recommended to use for new projects. ​

Javascript have grown more complicated with their requirements and huge possibilities they can accomplish. ​

CSS bundling preferences have also grown (although not as significant as Javascript), but providing tools to simplify the usage of this makes front-end development easier. ​


​ Make sure that your system has the latest Ruby installed. Check out Rodrigo’s post on Starting a New Ruby on Rails Project for details. ​

Let’s Get Started

Let’s start a project with this command:

bundle exec rails new . -a propshaft -j esbuild --database postgresql --skip-test --css tailwind

We use PostgreSQL instead of the default SQLite. Make sure that you have PostgreSQL installed on your machine. The fastest way is to install the Or get your hands dirty by installing it via Homebrew. ​

We are skipping the default test library here as well. We highly recommend using RSpec instead. ​

We will use Propshaft as the asset handler and skip Sprockets. ​

Here we use jsbundling-rails with esbuild for JavaScript building. A detailed comparison with webpacker is also discussed here for reference. ​

Tailwind CLI for CSS packaging is used here. Since we specified esbuild, Rails assumes that we will use a Node.js-based tool. On the Gemfile, cssbundling-rails will be added. ​

After this command, the Gemfile should contain the following entries: ​

gem "propshaft"
gem "jsbundling-rails"
gem "turbo-rails"
gem "stimulus-rails"
gem "cssbundling-rails"

Turbo-rails and Stimulus-rails are defaults. ​

The Javascript Packages

For the package manager, we will use Yarn, which is also the default choice of Rails. The package.json should look like this: ​

  "name": "app",
  "private": "true",
  "dependencies": {
    "@hotwired/stimulus": "^3.2.1",
    "@hotwired/turbo-rails": "^7.2.4",
    "autoprefixer": "^10.4.13",
    "esbuild": "^0.16.9",
    "postcss": "^8.4.20",
    "tailwindcss": "^3.2.4"
  "scripts": {
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets",
    "build:css": "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify"

The dependencies part lists all the packages our run-time code depends on. We have 2 Hotwire libraries and 3 libraries for CSS processing, namely: tailwindcss, postcss, and autoprofixer. ​

The scripts part contains scripts that can be invoked by Yarn. The build script (invoked via yarn build) triggers esbuild to look at files in app/javascript/*.* and bundle them to app/assets/builds. The build:css script calls Tailwind to output application.css, this can be invoked by yarn build:css. ​


​ Tailwind have a configuration file (tailwind.config.js). The content section is used to determine the files to be used for the final CSS bundle. ​

module.exports = {
  content: [

The applicaiton.tailwind.css file initializes Tailwind classes. ​

@tailwind base;
@tailwind components;
@tailwind utilities;

The app/javascript/application.js file imports Turbo and ./controllers, which installs Stimulus. The Stimulus documentation explains further how to use it with Turbo. ​

// Entry point for the build script in your package.json
import "@hotwired/turbo-rails"
import "./controllers"

The app/views/layouts/application.html.erb file should look like below. stylesheet_link_tag and javascript_include_tag will be converted to HTML that loads the files in the app/assets/builds. ​

<!DOCTYPE html>

    Test Project
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
    <%= yield %>

Run the App

​ Rails use the Foreman gem. This allows the application to start multiple processes together. On your bin/dev file, it checks if Foreman is installed and install it when it’s missing.

if ! foreman version &> /dev/null
  echo "Installing foreman..."
  gem install foreman
foreman start -f "$@"

The file contains the processes we want to start. The items below starts 3 processes: ​

  1. The Rails server
  2. yarn build which triggers esbuild to bundle JavaScript with a --watch parameter, so it runs in the background when files change, and
  3. The yarn build:css with a --watch parameter too. This triggers Tailwind to bundle our CSS. ​

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

​ Now let’s run the app by running bin/dev: ​

➜  testproject git:(main) ✗ bin/dev
21:26:43 web.1  | started with pid 6187
21:26:43 js.1   | started with pid 6188
21:26:43 css.1  | started with pid 6189
21:26:43 js.1   | yarn run v1.22.18
21:26:43 css.1  | yarn run v1.22.18
21:26:43 js.1   | $ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets --watch
21:26:43 css.1  | $ tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify --watch
21:26:43 web.1  | => Booting Puma
21:26:43 web.1  | => Rails 7.0.4 application starting in development
21:26:43 web.1  | => Run `bin/rails server --help` for more startup options
21:26:43 js.1   | [watch] build finished, watching for changes...
21:26:44 web.1  | Puma starting in single mode...
21:26:44 web.1  | * Puma version: 5.6.5 (ruby 3.1.2-p20) ("Birdie's Version")
21:26:44 web.1  | *  Min threads: 5
21:26:44 web.1  | *  Max threads: 5
21:26:44 web.1  | *  Environment: development
21:26:44 web.1  | *          PID: 6187
21:26:44 web.1  | * Listening on
21:26:44 web.1  | * Listening on http://[::1]:3000
21:26:44 css.1  |
21:26:44 css.1  | Rebuilding...
21:26:44 web.1  | Use Ctrl-C to stop
21:26:44 css.1  |
21:26:44 css.1  | Done in 111ms.

Note: If you haven’t created your database yet, run rails db:create on the console. ​

Moving Forward

​ You now have a fully functional Rails 7 setup and can start writing front-end code. From here you can now add TypeScript and React or other JavaScript framework you wish to use for our application. Each JavaScript library or framework you will add requires their own separate discussions which we will cover in succeeding articles.