Code and data can be on disk (SSD, NVMe).
As code is executed, Virtual memory will page-in the application code from the executable file, and it will page-in code from the shared library executable files, on demand. If code is not executed, it is not paged-in to RAM. If code has not been executed recently, and there is memory pressure from other demands on RAM, the RAM being used by the app’s idle code is freed, and the virtual memory page tables entries associated with that RAM change to point to the executable file, so the code can be paged back in if it is needed again.
Modified data in RAM, can be paged-out to a page/swap file on disk. This also happens when there is memory pressure and the chosen data pages have not been used recently. Again the virtual memory page tables are updated so they point to the location on disk where the data has been stored, so that if the app wants to use that data again, the operating system knows where to read it on disk and bring it back into RAM.
It is like having a small work space, but a storage room, you can move thing you have to work on between your work space and the storage area. You may have work space room for several things, but eventually you have to move things back to storage to make room for other things you need to work on.