The main goal is to reach 100% compatibility. Quite possibly your site uses contrib modules that are outdated and aren’t supported by the maintainer, and It’s good if these modules have at least automated Drupal 10 compatibility fixes. If not, then you need to create the patch with custom fixes.
With custom modules, it’s a bit easier. Some of the compatibility issues you can fix by Rector and some of them you need to update manually. Rector can save you a lot of manual work by automating code upgrades to Drupal 9, and 10. It’s safe time a lot. That is a good approach to use it.
Once you reach 100% compatibility, be prepared to deal with other issues. The problem is that many of these projects or modules have patches available to make them compatible, but the maintainers still need to commit them. Usually, site owners would download a project and then apply patches to ensure compatibility. However, on https://packages.drupal.org/8, these projects are listed as compatible only with earlier versions of Drupal. This restriction prevents Composer from downloading the project into a codebase with a newer version of Drupal, making the patching process difficult. Therefore, patching alone is not enough. A solution is needed to bypass the version constraints enforced by this remote endpoint. I used Drupal's Lenient Composer Endpoint. The Drupal community introduced a flexible Composer tool that adjusted the drupal/core constraint for packages. This adjustment aimed to remove obstacles in getting extensions installed via Composer to work effectively in transitioning modules to Drupal 9 compatibility. You can find more information on how to use it by following this link on drupal.org.
After updating Drupal all site functionality has to be checked for any errors. From my experience, there are always a few issues after updating, like missing dependencies, permissions, etc.