Docs menu

Ruby on Primcloud

How Primcloud detects a Ruby app, installs gems via Bundler, runs rake tasks, caches dependencies, and infers process types.

On this page

Primcloud detects Ruby apps from the presence of a Gemfile.lock, installs the Ruby version and Bundler version your lockfile pins, runs bundle install, executes rake assets:precompile when applicable, caches gems and asset fragments between builds, and, if you don't ship a Procfile, infers a web process from the gems your app uses. This page covers each of those phases and the config knobs that shape them.

Detection#

Primcloud runs the Ruby toolchain when the root of your repo contains a Gemfile.lock. A Gemfile alone is not enough; the lockfile has to be committed. If the lockfile is missing, the build fails with a "Gemfile.lock not found" error.

The lockfile also decides what else the build installs:

  • package.json or yarn.lock at the root: the Node.js toolchain is installed alongside, so JavaScript tooling used by asset compilation (e.g., jsbundling-rails, cssbundling-rails) is available. Node development dependencies are kept installed rather than pruned, so Rollup, esbuild, PostCSS, and similar are still around when rake assets:precompile runs.
  • A Bun lockfile at the root (bun.lock or bun.lockb, beside package.json): Bun is installed as well, installs your JavaScript dependencies with bun install --frozen-lockfile, and is on PATH when rake assets:precompile runs. Your Procfile, or the web process detected from your gems, still starts the app. See Bun package managers.
  • JRuby in the lockfile: a JDK is installed first.

Install phase#

Two things get installed before your gems: the Ruby interpreter and Bundler itself.

Ruby. Version resolved from the RUBY VERSION block of Gemfile.lock:

Gemfile.lock
RUBY VERSION
   ruby 3.3.9p0

If the lockfile has no RUBY VERSION block, Primcloud installs its default Ruby (currently 3.3.9). Pinning explicitly is recommended so a future default bump doesn't change your runtime unexpectedly.

Bundler. Version resolved from the BUNDLED WITH block of Gemfile.lock:

Gemfile.lock
BUNDLED WITH
   2.5.23

If the lockfile has no BUNDLED WITH line, Primcloud installs its own default Bundler (currently 2.5.23).

Gem install. bundle install runs on every deploy with the following environment applied:

Variable Value
BUNDLE_DEPLOYMENT 1
BUNDLE_FROZEN 1
BUNDLE_GEMFILE <app-dir>/Gemfile
BUNDLE_WITHOUT development:test
BUNDLE_PATH Points at the cached gem layer
GEM_PATH Same, for Ruby

BUNDLE_FROZEN=1 means restore fails if Gemfile.lock disagrees with Gemfile. That's usually what you want on a deploy. See Package managers → Lockfiles for the mechanics and how to loosen it if you need to.

Compile phase#

For Ruby, there's no separate compile step for your application code: Ruby is interpreted. "Compile" here means the asset pipeline and any other rake tasks your build depends on.

Rake task detection. After bundle install, the build runs rake -P to enumerate the rake tasks your app defines. If that command fails, the build aborts, since it can't tell what to run without it. Skip it entirely by leaving rake out of your Gemfile.lock and not shipping a Rakefile.

rake assets:precompile. Runs automatically if the task is present and no public/assets manifest is committed. A .sprockets-manifest-*.json or manifest-*.json under public/assets signals precompiled assets already live in git, and the build skips the task.

rake assets:clean. Runs after assets:precompile if defined. Its presence also flips asset caching on. Without it, precompile runs without cache and asset fragments aren't preserved between builds.

If your app is not Rails, has no Rakefile, and doesn't include rake in its lockfile, the build skips rake handling entirely and jumps straight to release.

Cache behavior#

The Ruby build writes cached layers that Primcloud persists in a per-app cache image between builds:

  • Ruby install layer: the resolved Ruby binary. Invalidated when the Ruby version, distribution, or CPU architecture changes.
  • Bundler install layer: the Bundler gem itself.
  • Gem cache layer: everything bundle install puts under BUNDLE_PATH. Invalidated on the same conditions as the Ruby layer, plus when Ruby's own version changes.
  • Asset cache layers: public/assets and tmp/cache/assets, each capped at 100 MiB. Loaded only if rake assets:clean is defined on your app. Least-recently-used files are pruned when the cap is hit.

bundle clean runs after every successful bundle install to prune gems that are no longer in the lockfile from the cached layer. The rubygems download cache (.gem files) is deleted after install to keep the final image small.

Release phase conventions#

Procfile takes precedence. If your repo has a Procfile at the root, Primcloud uses it verbatim to define process types, the same as every other language on Primcloud. See Pod Formations for the file format.

Auto-detected web process kicks in when there's no Procfile. Primcloud inspects Gemfile.lock to decide what to launch:

  • Rails (any app whose lockfile includes railties):

    Terminal
    bin/rails server --binding "[::]" --port "$PORT" --environment "$RAILS_ENV"
    
  • Rack (lockfile includes rack, config.ru present at the root):

    Terminal
    bundle exec rackup --host "[::]" --port "$PORT"
    
  • Neither: no default web process. The build still succeeds; you need a Procfile to declare one.

No auto-detected non-web processes. Workers, schedulers, one-off consumers: these all require a Procfile entry. Primcloud only ever generates a single default web process.

Port binding. The default commands read $PORT directly. If you write your own Procfile command, bind to $PORT explicitly. Primcloud sets it on the web formation only.

Runtime environment. Primcloud sets these on every process at runtime. All are marked as defaults, meaning anything you set in the Secrets panel takes precedence:

Variable Value Purpose
RACK_ENV production Read by Rack-based apps to select environment.
RAILS_ENV production Read by Rails to select environment.
RAILS_LOG_TO_STDOUT enabled Sends Rails logs to stdout so they land in the Logs page.
RAILS_SERVE_STATIC_FILES enabled Enables ActionDispatch::Static so Puma serves files from public/.
SECRET_KEY_BASE Randomly generated once per app, cached Rails cryptographic key. Override to rotate it.
MALLOC_ARENA_MAX 2 Reduces glibc memory arena count for a smaller footprint on multi-threaded Ruby.
DISABLE_SPRING 1 Disables the Spring preloader in production.
PUMA_PERSISTENT_TIMEOUT 95 Idle timeout aligned with modern HTTP router keepalives. Puma 7+ picks this up automatically.
JRUBY_OPTS -Xcompile.invokedynamic=false JRuby-only tuning; harmless on MRI.
PORT Assigned by Primcloud Set on web process types only.
PATH With <app>/bin, gem binstubs, and the Ruby binary prepended So bundle exec, rails, and app binstubs are on PATH.

<app>/bin sits ahead of gem-installed binstubs on PATH, so a committed bin/rails overrides the one Bundler would generate.