Prepare a staging deployment
- Commit
Gemfile.lock, a supported Ruby version declaration, and theaarch64-linuxlockfile platform. - Create a Cloud application from your repository and select its deployment branch.
- Attach a managed database and any cache or object storage the application needs.
- Copy application secrets through environment variables or Secrets Manager, including the existing
SECRET_KEY_BASEand the matchingRAILS_MASTER_KEY. - Configure the web command, deploy command, and background processes, then deploy to a staging environment.
Move from Heroku
Replace Heroku resources and process settings with their Cloud equivalents:
Cloud reads Procfile suggestions but doesn’t start every entry automatically. Review each command, especially worker and release commands, before deploying. Remove buildpack-specific scripts and replace any packages they installed with dependencies available in Cloud’s runtime.
Create a database backup using Heroku Postgres backups. Restore a copy into your target Postgres database using the connection details in View credentials. For managed Postgres, include
sslmode=require in the connection URL. Use compatible pg_dump and pg_restore versions, and review extensions, ownership, and permissions before restoring.
You can keep an existing S3 bucket or email provider during the move. Configure its credentials explicitly. If you replace S3 with Cloud object storage, follow the object storage migration guide and preserve Active Storage object keys.
Move from AWS
Inventory each AWS dependency before moving the application. Cloud can host the Rails web process and workers while you retain services such as SQS or SES through their public service endpoints.
A private RDS or ElastiCache address inside your AWS VPC isn’t automatically reachable from Cloud. Plan connectivity before relying on an external resource, or migrate it to an attached Cloud resource. Restrict any public endpoint and use verified TLS where the service supports it.
Cloud’s attached R2 bucket injects AWS-named variables. Keep R2 and AWS clients separate so SQS, SES, or an existing S3 bucket doesn’t inherit R2’s region or endpoint. Review credentials that previously came from an EC2 instance profile or ECS task role.
Export a consistent database snapshot using the source database’s tools. For MySQL imports, follow Importing MySQL data. For Postgres, restore a dump into a staging database first and check extensions, row counts, constraints, and generated ID sequences before cutover.
Differences from Kamal
Cloud builds your application from the repository and runs it on a managed Ruby runtime. Your Kamalconfig/deploy.yml, Dockerfile, accessory definitions, and host volumes don’t configure that runtime.
Move Kamal secrets into Cloud environment variables or linked secrets. Translate the web and worker roles into Cloud commands and clusters. Replace host-mounted uploads and SQLite files with object storage and managed databases. Review any custom OS packages from your Dockerfile against the Cloud Ruby runtime, including tools used for media processing.
Cloud handles the public HTTPS endpoint and deployment routing. Keep Rails’ HTTPS and proxy configuration, and test WebSockets and graceful shutdown before switching traffic. Use Cloud deploy commands for database preparation, and remove Kamal hooks that assume SSH access or a persistent host filesystem.
Move SQLite data to a managed database
Cloud instances have ephemeral filesystems, so a production SQLite database can’t remain on the instance. Plan a separate migration for the primary database and any SQLite databases used by Solid Queue, Solid Cache, or Solid Cable.- Back up each SQLite file and rehearse the migration using a copy.
- Add
pgormysql2to the production bundle and updateconfig/database.ymlfor the managed adapter. - Review migrations for SQLite-specific SQL and types. Run your test suite against the target database engine.
- Create the schema and import data using one migration method from the SQLite migration guide.
- Verify row counts, foreign keys, unique constraints, and generated IDs before deploying the application against the target.
schema_migrations with the migrations represented by that schema before running db:prepare. Otherwise, Rails may attempt to create existing tables.
Check boolean values, timestamps, JSON fields, and database-specific queries against the target adapter. Reset Postgres sequences after preserving numeric primary keys during import. Keep the original SQLite files as a recovery copy until you have verified the new database and its backups.
For Rails’ Solid components, configure the conventional cache, queue, and cable connections before attaching the primary database. Cloud can then create their secondary databases. Decide which cached data can be discarded and drain pending jobs before moving the queue database.
Keep or replace Delayed Job
You can continue using Delayed Job on Cloud. Keepdelayed_job_active_record, the daemons gem, and the existing jobs table in your production setup, and configure Active Job in config/environments/production.rb:
bin/delayed_job executable, add a custom background process that runs in the foreground:
bin/rails generate delayed_job locally and commit the generated executable. If the jobs table is also missing, use bin/rails generate delayed_job:active_record to generate its migration, review it, and apply it through your deploy command. Avoid generating a duplicate migration if the delayed_jobs table already exists. Keep the worker’s cluster awake when jobs must run without HTTP traffic.
To replace Delayed Job with Solid Queue or Sidekiq, install and configure the new backend in staging first. Active Job abstracts the enqueue API, but it doesn’t translate stored Delayed Job records into another backend’s queue.
Stop new enqueues to Delayed Job during cutover and let its workers drain pending jobs. Inventory scheduled and failed jobs, then explicitly re-enqueue the jobs you need through application code after changing the adapter. Direct calls such as object.delay also need to move to job classes or another supported API. Keep jobs safe to retry so a cutover retry doesn’t duplicate a payment or email.
Switch production traffic
- Rehearse the database and object-storage imports, and record how long the final copy takes.
- Pause writes on the source application and stop producers of new jobs. Drain or record pending and scheduled jobs before stopping its workers.
- Take the final database backup and copy the remaining data and uploaded objects.
- Deploy Cloud against the final database, then test sign-in, a write, an upload, a background job, and email delivery.
- Add and verify your custom domain, update DNS, and check HTTPS and WebSocket connections through the production hostname.

