1. Name the date that forces the work
Start with the event: a host notice, a questionnaire, a scanner report. Write the component, the version and the date, and check the vendor's own page for its published date. If the vendor publishes none, record that. Work that has no date can wait; work that has one sets the order.
- Read the guide on reading support dates correctly before comparing two vendors.
- Record the day you read each page.
2. Record the test baseline
Run the existing tests on a copy and save the result as passing, failing with names, or unable to run. Without this, no later failure can be attributed. If there are no tests, write the flows that matter and how you check them by hand.
- Use synthetic data; no production data or secrets.
- The baseline guide explains each state and what to do when tests cannot run.
3. Inventory and rank everything that is behind
List the runtime, framework and direct dependencies with versions, support status and prerequisites, then rank the steps. The worked register shows what this looks like for an invented app. This is the fixed inventory and plan job, and it is the right first purchase when more than one component is behind.
- Look for steps that depend on a runtime or a dependency you have not yet moved.
- Mark unknown dates and who can resolve them.
4. Move the runtime when the runtime is the blocker
If the runtime is past its date or blocks a framework, move it first and alone. For Node.js, choose a line from the project's schedule and find every place the version is set. For Python 3.9 or 3.10, find removed modules and compiled packages. For Ruby, upgrade it before Rails, as the Rails guide advises, but only to the latest Ruby your current Rails minor supports: the guide gives minimum Rubies, and a published compatibility table recommends an older Ruby for Rails 7.0 than for 7.1 and later.
- Check compiled modules before committing to a date.
- Keep the runtime change separate from the framework change.
5. Move the framework one step at a time
For Rails, take each minor version in turn with the tests run at each; a Rails 6 app needs its autoloader checked first. For Express, convert path patterns and error handling and check real URLs before and after. A framework step is accepted on its own evidence, not folded into the runtime step.
- Use the Rails and Express guides for the documented changes to test.
- A step that is bigger than planned is re-scoped before it continues.
6. Handle build tools and front-end code
A retired JavaScript build, such as Webpacker in Rails, needs a decision before or after the version steps, not during them. A Webpack single-page app can move to Vite as its own step, and a folder can be converted to TypeScript. Replace an unsupported jQuery or AngularJS feature one at a time, with its contract written down first.
- List what the old build does before choosing a successor.
- Keep the type check as a separate command when moving to Vite.
7. Move data and hosting last, and once
Moving to a new host or database engine is best done after the runtime and framework are supported, so the app moves once. Use the move-order map for the copy, reconciliation, write freeze and way back. A change to one column of a large table inside the same database is a smaller version of the same problem, with its own stepwise guide.
- Do not combine a version upgrade with a database move in one change.
- A database copy is rehearsed into an empty target first.
- A column change on a large table is stepped and reconciled row by row, not run as one blocking statement.
8. Keep it supported
After a programme, the work shifts from projects to upkeep: monthly patch and minor updates with tests, advisory triage and early warning of support dates, or a second test run on the next version that shows what would break. Neither promises that a version stays supported or that every advisory has a fix. Prices are untested proposals and payment follows agreed checks.
- Re-read vendor pages every month; dates change.
Sources and limits
- Rails guides: upgrading Ruby on Rails Checked 2026-10-11.
- The guide recommends starting from passing tests, upgrading Ruby before Rails, and moving one minor version at a time.
- FastRuby: Rails and Ruby compatibility table Checked 2026-10-11.
- The table, updated 30 September 2026, recommends Ruby 3.3 for Rails 7.0.Z and Ruby 3.4 for 7.1.Z, 7.2.Z, 8.0.Z and 8.1.Z.
- Node.js: previous releases Checked 2026-10-11.
- Production applications should only use Active LTS or Maintenance LTS releases.
- Python developer guide: versions Checked 2026-10-11.
- Python 3.9 and 3.10 are end of life; 3.11 and later receive security fixes.