Best Practice Storage Implementation

What is the best practice for the storage of the implementation contract?

Proxies since v5 are implementing EIP1967 storage slots. Is the best practice for the implementation contract to follow this pattern, or is the best practice to just use regular contract wide storage slots via normal storage variables?

Are there any benefits/drawbacks already known to using either of those we should be aware of?

To clarify, OpenZeppelin Contracts v5 uses ERC-7201: Namespaced Storage Layout.

In general, we recommend also using namespaced storage in your own implementation contracts, but it is not a requirement. See my comments in Must a child contract use the namespaced storage pattern - #2 by ericglau and Do I need to use storage gaps when importing upgradeable contracts? - #4 by ericglau

Thanks @ericglau - yes, I meant ERC7201 for the implementation, my bad. The docs mentioned the 1967 for the proxies and I copied them a bit too quickly...

I had another question a while back about proxy upgrades from OZ 0.4 to 0.5, which might make this a viable upgrade path. When someone upgrades from Proxies from V4 to V5 then the slots are reset back, so the gap is missing, because the Proxies are not using slots from slot 0 on instead set their own custom storage slot. Would it be a feasible strategy to upgrade and just set the slot for the implementation to the right slot after the proxies used from 0.4 and use a custom namespaced storage layout? If yes, do you know any rather quick method to find out where the proxies storage slots ended and the implementation started? It is safe to say its like 50 (the former variables plus the gap) times all the base contract it uses?

Sorry I don't understand your question or what you are suggesting. In any case, using different storage locations after an upgrade would lead to loss of previous state, unless you have a way of migrating or continuing to read state from the old locations.