Can we move metadata between Unlocked Packages?

John answered the question already very well but I want to draw your attention to this hidden documentation gem by the Packaging PM Dileep Burki. It helped to feel safe with Unlocked Packages.

enter image description here

In those sections, it really describes how and that unlocked packages were designed for such refactorings.

How can I refactor my package?

Let’s suppose you have installed ver 1 of your unlocked package pkg1. As part of refactoring your App, you decide to move some metadata from pkg1 to a new package pkg2.

You will refactor the package by following these steps:

  1. Identify the metadata that you want to move out of pkg1.
  2. Remove metadata identified in step 1 from pkg1 repo and create ver 2 of pkg1.
  3. Add the metadata identified in step 1 to a different DX folder / project / repo and create ver 1 of pkg2 using that metadata. You may add other metadata to complete pkg2.
  4. After proper testing and UAT, install ver 2 of pkg1 in the org where ver1 of pkg1 has been installed.
  5. Install ver1 of pkg2 in the same org.
  6. At the end of step 5, the metadata identified in step 1 would have migrated from pkg1 to pkg2.

Can I downgrade my package?

You should consider any downgrade of a package carefully. Package downgrades can fail due to dependency scenarios. For E.g.: if ver 3.0 has an apex class that is referenced by another apex class in a different package, downgrading to ver 2.0 would fail with a user-friendly error message if that apex class is not present in ver 2.0 of the package.

In the context of packaging, a downgrade is installing a lower version of a package on top of a higher version. For E.g.: this is when you try to install ver 2.0 of your package in an org where ver 3.0 has been installed.

When you downgrade a package, the following occurs:

  1. The metadata of the package version (ver 2.0 in this example) is deployed to the target org.
  2. Any metadata that is present as part of the package in the installed org (ver 3.0 metadata in this example) is modified, deleted or deprecated based on whether they are present in the version being installed. For E.g.: an apex class will be modified to the ver 2.0 copy of it as part of the downgrade. If a custom object foo__c is not present in ver 2.0 but present in ver 3.0, foo__c is marked deprecated (See here for more info about what deprecated means in this context). If a report object is not present in ver 2.0 but present in ver 3.0, the report is deleted from the org.

Is there a process that allows us to safely move a piece of metadata from a package to one of its dependent packages?

Yes. Once a piece of metadata is released via an unlocked package, you can remove it from the package down the road in a subsequent package version. So the metadata item is no longer in the latest package version. When you install that version to an org where a previous version was installed, the installation event will effectively "release the metadata component back to Happy Soup". Pay attention to the --upgradetype flag on the force:package:install command. See documentation about this flag. Don't worry about screw ups - I have "screwed up" several times myself. This will help you adjust things.

Also, can we move metadata from a dependent package to a base package as well?

Oh yes. Basically, it is the same approach as above. Identify the components you want to move. Release them from the original package. Include them in the new package. Once you install new package to the org, it "assumes ownership" of that "loose metadata."

Hope this helps.