Ruby on Rails Cloud Migration in 2026: What CIOs Should Check Before Moving

Written by

The Rails application boots on its new cloud host. The home page loads, staff can sign in, and the migration looks finished. Then someone downloads an old attachment and gets an error. A scheduled export runs twice. The database reaches its connection limit while the web servers still have spare capacity.

Those are useful problems to plan around. A Ruby cloud migration moves more than a repository and a database.

Consider an established Rails billing portal with PostgreSQL, background jobs, customer document uploads and payment webhooks. The project described here is a planning example, not a reported customer migration. Its goal is to move hosting without losing records, repeating charges or making the application harder to operate.

Broader discussions of cloud challenges in 2026 provide context. For the team responsible for this Ruby application, though, the useful questions start in the repository and the current production environment.

1. Inventory the Ruby application before choosing its new home

Ask an engineer to demonstrate how the application is built from a clean checkout. Record the Ruby and Rails versions, the Bundler version, the contents of Gemfile.lock, and any operating-system packages needed by native gems.

A build that succeeds on one developer’s laptop proves little about a different processor architecture or container image. Compile the dependencies in the target environment and run the application tests there.

The inventory should also include work that sits outside the web process:

  • Active Job or other background workers, including their queue backend.
  • Scheduled Rake tasks and any cron entries on the old server.
  • Active Storage files or uploads handled by another library.
  • Payment callbacks, email delivery, external APIs and their credentials.
  • Redis, if used for queues, caching or other application features.

Redis used as a cache is not interchangeable with Redis holding queued work. Losing cached results and losing pending jobs have different consequences.

Give every dependency an owner and a migration step. Otherwise, the forgotten monthly billing task may be the first thing that tells you the move was incomplete.

2. Keep the Rails monolith unless there is a reason to split it

Moving to a cloud provider does not require turning a working Rails application into microservices.

For the example billing portal, keeping the application intact while moving PostgreSQL to a managed service may be a reasonable first stage. Rehosting can also be useful when the immediate problem is an expiring server contract or unreliable hardware. Neither approach guarantees lower costs; both need measurement.

A redesign belongs in the plan when it addresses a known limitation. Perhaps document generation blocks web requests, or a large import competes with customer traffic. Running that work in separately scaled job processes may solve the problem without introducing multiple services.

The Cloud strategy should describe which problems the move solves, what stays together and what the team will maintain afterward. A new orchestration platform adds little if nobody can diagnose it during an outage.

Where practical, test major Ruby or Rails upgrades separately from the hosting change. Combining a runtime upgrade, database upgrade and platform move makes a regression harder to trace.

3. Size Puma and Active Record together

For Rails teams, instance sizing needs to account for the Ruby process model.

Puma uses worker processes and threads. With CRuby, adding threads does not make Ruby code execute in parallel within one process, although threads can overlap waits for I/O. More workers can use additional CPU cores, but they also consume memory.

Benchmark representative traffic on the proposed host. Include a busy invoice page, a document upload and an export request. Compare response-time percentiles, memory usage and throughput before settling on worker and thread counts.

Then calculate the database connection budget. Suppose four web instances each run two Puma workers, with an Active Record pool of five connections per worker. Those web processes can require up to 40 connections to that database. Two job processes with pools of ten add another 20.

That is 60 potential application connections before administrative access, migrations or overlapping deployments. It is an illustration, not a recommended configuration.

Account for every process and database pool, including the temporary capacity used during rollout. Autoscaling web instances can worsen a database bottleneck if connection demand grows unchecked.

4. Move queued work and uploaded files deliberately

Active Job provides a Rails interface for background work; durability and execution depend on the selected backend and its configuration. Record what happens to queued, scheduled and running jobs when the old environment shuts down.

For the billing portal, distinguish a job that renders a PDF from one that submits a payment. Retrying a report might waste compute. Repeating a charge is a different problem. Use stable operation identifiers and payment-provider idempotency controls where available, and reconcile uncertain outcomes.

During cutover, decide which environment owns scheduled billing and incoming webhooks. Do not leave both old and new schedulers creating the same work.

Uploaded documents need their own migration. Active Storage records in PostgreSQL do not contain the file bytes stored in an object store or on disk. A database restore alone therefore does not restore those documents.

Active Storage offers a mirror service for transitions between storage services, but mirroring is not atomic. Copy existing objects, verify the inventory and resolve failed copies before switching the primary service. Test older attachments as well as new uploads.

If files currently live on local disk, decide how they will remain available when an instance is replaced or another instance serves the next request.

5. Rehearse the database cutover and the rollback

A successful database copy is only part of the cutover.

First, restore a recent backup into an isolated environment and test representative workflows. Keep production email and payment side effects disabled during the rehearsal. Record the time required so the maintenance estimate is based on a run rather than a guess.

Next, establish how writes will move. For this example, a planned write pause may be acceptable. Another application might need replication and a more involved switchover. Either way, the plan must prevent the old and new environments from becoming independent writers with diverging records.

Coordinate web requests, background workers, scheduled tasks and webhooks. Pausing the website does not necessarily stop the other sources of writes.

Schema changes also matter. Avoid dropping a column that an old application process still needs during a rolling deployment. Add compatible structures first, deploy supporting code, backfill data and remove obsolete structures only after the old code is gone.

Finally, define the rollback boundary. Switching traffic back to an old server is unsafe if its database no longer contains the latest writes. Specify how those writes will be preserved or reconciled, and who decides whether to recover forward instead.

6. Price the Rails workload, including any AI features

An estimate that covers only web instances misses much of the operating cost.

For the billing portal, include PostgreSQL, job workers, queue storage, backups, uploaded documents, network transfer, monitoring and staging environments. Temporary duplication during migration also belongs in the budget.

Track cost alongside workload measures. Cost per completed invoice batch or per active customer can be more useful than a cloud total with no explanation of what changed. Investigate growth in failed jobs, repeated exports or verbose logs before assuming the answer is a larger budget.

AI needs a separate workload decision. Suppose the product team wants summaries of customer support conversations. A Ruby service that calls a hosted model API does not, by itself, require GPU instances for the Rails application.

It does require decisions about permitted data, request limits, timeouts, retries and what users see when the service is unavailable. Long-running calls may belong in a background job so they do not occupy a web request for their entire duration.

Deloitte’s discussion of AI infrastructure and inference costs is relevant here: repeated model use changes the cost calculation. Measure the actual feature before committing to dedicated inference infrastructure.

Budget alerts should have a named responder. If a feature needs a hard spending boundary, implement and test suitable quotas or controls rather than assuming an alert stops consumption.

7. Make production ownership part of the migration

Moving secrets into a new environment deserves the same care as moving the database.

Keep production secrets out of source control and container images. If the application uses encrypted Rails credentials, protect the decryption key separately. Restrict database and object-store permissions to what each workload needs.

Check the application behind its new proxy or load balancer. Verify HTTPS handling, permitted hosts, callback URLs and access to administrative tools. Rails protections still need the correct deployment configuration.

Logging also needs review. Parameter filters can help protect request data, but custom log statements and monitoring integrations may capture information independently.

Before signing off, ask the team to demonstrate a deployment, a failed-job investigation and a backup restoration. Name the people who receive alerts and can authorize recovery work.

For the CIO, success should be visible in the application’s behaviour: invoices remain correct, jobs complete, documents stay accessible and the team can explain the bill. A Rails cloud migration is ready when those checks pass and the recovery procedure has been rehearsed.