Updated November 10, 2026. Tested with Ruby 3.1, Rails 7.2.4 and the setup from part 1, plus tailwindcss-rails 4.7 (Tailwind CSS v4) and daisyUI 5, using Docker Desktop on macOS.

In the previous post we walked through getting a fully dockerized Ruby on Rails app up and running. In this post we’ll expand on it by adding Tailwind to the basic setup so that we can take advantage of Tailwind utility classes in our development. This combo can be really productive! We’ll finish up by adding daisyUI, a component library built on top of Tailwind.

Step 1: basic Ruby on Rails setup

If you haven’t already, follow the instructions in the previous post to set up a fully dockerized Ruby on Rails app.

Step 2: add Tailwind

Add the tailwindcss-rails gem to your Gemfile. We’ll add foreman too, which we’ll use in a minute to run more than one process at a time:

gem "tailwindcss-rails"
gem "foreman", group: :development

Because our gems are installed when the Docker image is built, rebuild the image, then run the Tailwind installer inside the container:

docker-compose build
docker-compose run --rm web rails tailwindcss:install

The installer sets a few things up for you:

  • app/assets/tailwind/application.css: your Tailwind entry point. This is where you configure Tailwind.
  • app/assets/builds/tailwind.css: the compiled CSS that your app actually serves. This is generated, and Rails git-ignores it.
  • Procfile.dev and bin/dev: a way to run the Rails server and the Tailwind watcher together.
  • A stylesheet_link_tag "tailwind" in your layout.

Step 3: run Rails and Tailwind together

In development, Tailwind needs to watch your files and recompile whenever you use a new utility class. That’s a second long-running process alongside the Rails server, and that’s what Procfile.dev and foreman are for. The Procfile lists the processes to run, and foreman starts them all. The generated Procfile.dev needs one tweak for Docker: tell the Rails server to listen on all interfaces, otherwise it won’t be reachable from outside the container.

web: bin/rails server -b 0.0.0.0
css: bin/rails tailwindcss:watch

Next, update the web service in docker-compose.yml to start everything with bin/dev, and keep its stdin open:

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bin/dev"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    stdin_open: true
    tty: true
    depends_on:
      - db
    environment:
      RAILS_ENV: development

The stdin_open and tty lines matter. Tailwind v4’s watcher quits as soon as it sees its input stream close, which is what happens to a background process in a container by default. Without them, the watcher starts, compiles once, and exits, and foreman shuts everything down with it.

Step 4: try it out

Let’s make a page to test it. Generate a controller and make it the home page:

docker-compose run --rm web rails generate controller home index

In config/routes.rb, add:

root "home#index"

Then put some Tailwind classes in app/views/home/index.html.erb:

<h1 class="text-4xl font-bold text-indigo-600 p-8">Hello, Tailwind!</h1>

Start everything up:

docker-compose up

You should see output from both web.1 and css.1 in your terminal. Visit http://localhost:3000 and you’ll see a big indigo heading.

Now try adding another class to the markup, such as bg-amber-200, and save. The watcher recompiles the CSS in the background, so just reload the page and the change should show up. There’s no need to restart anything.

Step 5: add daisyUI

daisyUI is a Tailwind plugin that adds ready-made component classes like btn, card and modal, so you don’t have to assemble every component from raw utilities.

Since we’re not using Node in this setup, we can use daisyUI’s standalone file. Download it into the Tailwind folder, from the project root:

curl -sLo app/assets/tailwind/daisyui.mjs https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.mjs

Then load it as a plugin in app/assets/tailwind/application.css:

@import "tailwindcss";
@plugin "./daisyui.mjs";

With docker-compose up still running, the watcher picks up the change. Try a component in app/views/home/index.html.erb:

<button class="btn btn-primary">daisyUI button</button>

Reload the page and you’ll have a styled button.

What’s next

We now have a Dockerized Rails app with Tailwind compiling as we work, and a component library to build with. In the next post, we’ll add hot reloading, so that the browser updates automatically whenever you save a change.