A full answer to this question should detail the difference between
CREATE2 opcodes, which are the two opcodes in the EVM for creating new contracts; it should be possible to do this using either as long as for
CREATE you use the same keypair across all chains, and have the same nonce on all chains. This article also details how to use
CREATE2 for the same task (provided initcode is consistent across all chains), which should be easier, all things considered. I'm going to gloss over that all because of CREATE3, though.
There has been some work recently nicknamed CREATE3. This isn't an actual opcode in the EVM (yet), but rather some work done to make contracts which are themselves contract factories which make it a bit easier to deterministically generate addresses. The first implementation I'm aware of is 0xsequence's here, though Rari also ships an implementation in Solmate.
There is a README in 0xsequence's repo explaining how to use the contract. The basic uptake would be that you could import this library, and as long as the contract bytecode is identical across all chains, just using the same salt in the
create3 function (or
deploy in Solmate) should ensure that the address of all deployments is identical.