# docker-rails-example: a Rails app where Docker Compose is the only way to run it

> nickjj's docker-rails-example is a production ready Rails 8.1 app that runs under Docker Compose with PostgreSQL, Redis, Sidekiq and a standalone Action Cable, and it is deliberately opinionated about the parts that matter in containers: logging to STDOUT, secrets from an .env file, and no credentials file. The run script is the interface, and everything runs through it.

**nickjj/docker-rails-example** — A production ready example Rails app that's using Docker and Docker Compose.

- Repository: https://github.com/nickjj/docker-rails-example
- Stars: 1,079 · Forks: 227
- Language: Ruby
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/nickjj-docker-rails-example

## What it is: a worked example, not a scaffold

The repository is described as a production ready example Rails app using Docker and Docker Compose, and the README frames the choice of use explicitly. You could use this example app as a base for your new project, or as a guide to Dockerize your existing Rails app. The second framing is the more interesting one, because the author describes the example as minimal but wiring up a number of things you might use in a real world Rails app, while at the same time not being loaded up with a million personal opinions. The Docker bits are described as an accumulation of Docker best practices based on building and deploying dozens of assorted Dockerized web apps since late 2014. The app is using Rails 8.1.3.1 and Ruby 4.0.6, and the version numbers in the screenshot are placeholders because they get updated regularly.

## The stack, and the removals that are the actual content

The back end is PostgreSQL, Redis, Sidekiq for background work through Active Job, a standalone Action Cable process and ERB for views. The front end is esbuild, Hotwire Turbo, StimulusJS, TailwindCSS and Heroicons. The notable opinions section is the part worth reading, because the removals are as informative as the additions. The solid_* adapters are removed for now, and so are Kamal and Thruster, for now, which tells you this is a container-first project that does not assume a deployment tool. The generated code around PWA and service workers is removed, Brakeman is removed, and Procfile.dev has been removed since Docker Compose handles this. On the additions, there is a pages controller with a home page, an up controller with two health check related actions, and custom 502.html and maintenance.html pages. The route for Sidekiq's dashboard is ready to be used but commented out for safety.

## Configuration decisions: STDOUT logging and secrets from an .env file

Three configuration changes are the reason a Dockerised Rails app usually works at all. The application logs to STDOUT so that Docker can consume and deal with log output, rather than writing to log files inside the container that nobody collects. Credentials are removed, with secrets loaded in with an .env file, which is the piece that changes how you think about deployment, since there is no credentials file to keep out of version control. And a bunch of configuration settings are extracted into environment variables, with config/database.yml rewritten to use environment variables. There are also two initializers worth naming, one enabling YJIT and one enabling a rack mini profiler for profiling Hotwire Turbo Drive. And a .yarnc sets a custom node_modules/ directory, so the JavaScript dependencies live somewhere deliberate inside the container rather than wherever the base image put them.

## The compose file: profiles, a two stage image and an assets service

The compose file is the centre of the project and its structure is worth reading. There are two extension templates, x-app and x-assets, both anchored on the same set of build args, an env_file pointing at .env, a restart policy defaulting to unless-stopped, a three second stop_grace_period and a tty. The app template's depends_on uses condition service_started with required false for postgres and redis, which is a Docker Compose v2 feature and the reason the README states the project uses features that only work with Docker Compose v2 2.20.2 and newer. The app service mounts a volume for the public directory, while the assets service mounts the whole project and runs under the assets profile. The services are postgres, redis, web, worker and cable, and the .env.example decides which of them start by setting COMPOSE_PROFILES, defaulting to postgres,redis,assets,web,worker,cable in development.

```yaml
postgres:
  image: "postgres:18.6-trixie"
  profiles: ["postgres"]
  restart: "${DOCKER_RESTART_POLICY:-unless-stopped}"
  stop_grace_period: "3s"
  volumes:
    - "postgres:/var/lib/postgresql"

redis:
  image: "redis:8.10.1-trixie"
  profiles: ["redis"]
  volumes:
    - "redis:/data"
```

## The Dockerfile, and why it builds twice

The Dockerfile has an assets stage and an app stage, and the assets stage is where the front end is built. It starts from ruby:4.0.6-slim-trixie, installs build-essential, curl, git, libpq-dev and libyaml-dev, then adds the NodeSource apt repository and installs Node 24, enables corepack, and cleans the apt lists and the documentation directories to keep the layer small. It creates a ruby group and user with the APP_UID and APP_GID build args, defaulting to 1000, and makes a /node_modules directory owned by that user, so the container never runs the app as root and the node modules are writable. It copies the Gemfile and runs bundle install, then copies package.json and the yarn files and runs yarn install, then copies the application. Assets are precompiled only when the environment is not development, using a SECRET_KEY_BASE_DUMMY value. The app stage is a much slimmer image with the same base but only curl and libpq-dev.

```dockerfile
FROM ruby:4.0.6-slim-trixie AS assets
LABEL maintainer="Nick Janetakis <nick.janetakis@gmail.com>"

WORKDIR /app

ARG APP_UID=1000
ARG APP_GID=1000

COPY --chown=ruby:ruby Gemfile* ./
RUN bundle install

COPY --chown=ruby:ruby package.json *yarn* ./
RUN yarn install
```

## Running it: clone, copy the env file, build, and set up the database

The running instructions are short. You need Docker installed, and on Docker Desktop you need Compose v2 enabled, while on native Linux you install it as a Docker plugin. On Windows you are expected to be inside WSL or WSL 2, because the commands are shell commands. Then you clone the repository into a directory, copy .env.example to .env because the real one is git ignored, and run docker compose up --build, with the warning that the first time takes five to ten minutes depending on your connection and hardware because it downloads Docker images and builds the Ruby and Yarn dependencies. In a second terminal you run ./run rails db:setup, and then you visit http://localhost:8000. If you get a port in use error, the README points you at the DOCKER_WEB_PORT variable documented in the .env file.

```sh
git clone https://github.com/nickjj/docker-rails-example hellorails
cd hellorails
cp .env.example .env
docker compose up --build

./run rails db:setup
```

## The run script is the interface, and it is the piece to copy

Everything goes through the run script, and the README highlights it as one of the two files of interest alongside the .env. It runs the application inside the container rather than on the host, so the local environment does not need Ruby or Node installed. The commands documented include ./run rails db:setup, ./run format, where the shorthand -a flag or --auto-correct applies any auto-correctable issues, ./run quality which lints and formats all files, and ./run test, with a -b flag that also builds the JavaScript and CSS bundles. There is also ./run rails secret, referenced from the .env example as the way to generate a more secure SECRET_KEY_BASE. For a team Dockerizing an existing application, this script is the artefact to copy, because it is what makes the container feel like the development environment rather than a packaging step you do at the end.

```sh
./run format
./run format --auto-correct
./run quality
./run test
./run test -b
```

## Licence, upkeep and what the repository does not cover

The licence is MIT, with the LICENSE file at the repository root, and the primary language is Ruby. The last push to the repository was on 2026-09-15, the repository is not archived, and there are no GitHub releases, since the deliverable is a repository you clone rather than a versioned artefact. The repository layout is a standard Rails application with the container files added, so there is a Dockerfile, a compose.yaml, a .dockerignore, a .env.example, a .hadolint.yaml for linting the Dockerfile, a .rubocop.yml, a Rakefile, a run script, a cable/ directory for the Action Cable process, a lib/ directory and a vendor/ directory. What the project deliberately does not provide is a deployment tool, since Kamal and Thruster are removed for now, and the README's additional resources section points at Docker and Ruby on Rails learning material and a separate deploy to production guide, which tells you where the project expects you to go next once the container is running.

## Conclusion

docker-rails-example suits a developer who wants a Rails deployment that works identically on a laptop, in CI and on a server, or who is Dockerizing an existing Rails application and wants a worked example of the decisions rather than a starting scaffold. It is the wrong choice if you want a Rails app with no container runtime anywhere, and a poor fit if you need a deployment tool already built in, because the README removes Kamal and Thruster for now and the compose file is the whole story. Before adopting it, read the .env.example, because the profiles and environment variables there decide which services start, and note the Docker Compose requirement of 2.20.2 or newer for the optional depends_on behaviour the project uses.

## FAQ

### What is the docker-rails-example project?

It is a production ready example Rails app that runs under Docker and Docker Compose, which you can use as a base for a new project or as a guide to Dockerize an existing Rails app. It uses Rails 8.1.3.1 and Ruby 4.0.6, with PostgreSQL, Redis, Sidekiq and a standalone Action Cable process.

### How do I run the docker-rails-example app?

Clone the repository, copy .env.example to .env because the real one is git ignored, run docker compose up --build, then run ./run rails db:setup in a second terminal and visit http://localhost:8000. You need Docker Compose v2 2.20.2 or newer, and on Windows you are expected to work inside WSL or WSL 2.

### How does the example handle secrets and logging?

Credentials are removed and secrets are loaded in with an .env file, and a bunch of configuration settings are extracted into environment variables, with config/database.yml rewritten to use them. The application logs to STDOUT so Docker can consume the log output rather than writing log files inside the container.

### What does the run script do?

It is the interface for everything, running commands inside the container so the host needs no Ruby or Node install. The documented commands include ./run rails db:setup, ./run format with an --auto-correct shorthand of -a, ./run quality to lint and format all files, ./run test with a -b flag that also builds the JS and CSS bundles, and ./run rails secret to generate a SECRET_KEY_BASE.

### Which services does the compose file define and how are they enabled?

The services are postgres, redis, web, worker and cable, each with a profile, and the .env.example sets COMPOSE_PROFILES, defaulting to postgres,redis,assets,web,worker,cable in development. The app template's depends_on uses service_started with required false, which is a Docker Compose v2 feature that needs 2.20.2 or newer.

## Sources

- [Issues](https://github.com/nickjj/docker-rails-example/issues)
- [License: MIT](https://github.com/nickjj/docker-rails-example/blob/main/LICENSE)
- [nickjj/docker-rails-example on GitHub](https://github.com/nickjj/docker-rails-example)
- [README](https://github.com/nickjj/docker-rails-example/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nickjj-docker-rails-example
