You can do both!
Your general file can loosely define dependencies like greater than this version, less than this version, skip this version, etc
Then you “lock” and it builds a dependency tree with the newest version of everything that satisfies your loose requirements.
Then you can choose to install dependencies
from your lockfile, which is exact frozen versions OR you can re-run the lock later, which will again attempt to update everything to the latest versions that satisfy your loose constraints