There is a famous library which allows to deploy minimal proxy contracts.
However, unlike traditional proxy contracts that are designed for upgradeability, minimal proxy contracts are fixed to one implementation.

This characteristic makes them a cost-effective strategy for deploying numerous contracts that share the same logic but may operate with different state data.
A great advancement in this area is the introduction of the ClonesWithImmutableArgs library. This library enhances the utility of minimal proxy contracts by allowing the inclusion of immutable variables during the deployment process. These variables are then accessible in each delegate call made to the implementation contract.

The advantage of the ClonesWithImmutableArgs mechanism is the innovative approach to passing immutable arguments. First of all, we need to understand that the proxy contract is deployed with immutable arguments.
When now a call is made to a proxy contract, the immutable arguments are appended to the end of the calldata for the delegate call.

Once extracted, these arguments can be used just like any other variables within the business logic of the contract.

The ability to deploy proxy contracts with immutable arguments has several notable benefits:

Efficiency: It significantly reduces the gas costs associated with deploying multiple instances of a contract, as the core logic resides in a single implementation contract. The only variation among the clones are the immutable arguments, which are efficiently passed via calldata.

Flexibility: Developers can create contract instances that behave differently based on the immutable parameters provided at deployment. This allows for a broad range of applications without sacrificing the benefits of code reuse and minimal deployment costs.

Simplicity: By utilizing the ClonesWithImmutableArgs library, developers can streamline their contract architecture. It simplifies the management of multiple contract instances with similar logic but different initialization parameters.

A nasty bug can be implemented when using this concept:
If implementations expose a function that executes a delegatecall to an address which is based on the immutable args, a malicious user can directly call the implementation by padding any arbitrary calldata, including such an address with a self-destruct function.

This can then be abused to selfdestruct the implementation. Oh wait, there was something with selfdestruct a few days ago …