I was wondering why, in treasury_pallet, there is a recurrent I generic parameter along with T, almost always used to specify lifetime:

    #[pallet::generate_store(pub(super) trait Store)]
    pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);

ex for lifetime:

    pub(crate) type ProposalCount<T: Config<I>, I: 'static = ()> = StorageMap<

Other pallets doesn't have it, so why? Does it have a specific use? Can I remove it if I'm making a different pallet forked from Treasury? I'd like some enlightenment on this

2 Answers 2


This is not a lifetime generic, but a second generic parameter used to specify the instance of a pallet, as @joepetrowski mentioned.

What an "instance" means is basically we can use all the same pallet logic, but just create a new instance of storage items by changing the storage prefix used.

You can read here for more context on how storage key generation happens in the background.

But at a high level, every storage key is:

hash(pallet_name) + hash(storage_name)

So this second generic modifies the pallet_name to be unique by adding a prefix to the pallet name, and modifying the storage key like so:

hash("Instance1" + pallet_name) + hash(storage_name)

End of the day this is half Substrate magic, in the way that instances modify the behavior of storage key generation, but this is also just normal Rust generics too.

If we had two structs that were my_pallet::Pallet<T>, they would not be different types. However, my_pallet::Pallet<T, Instance1> and my_pallet::Pallet<T, Instance2> are completely different types in the Rust type system, and would prevent many errors that could occur otherwise.

  • Ok !! everythings make sense now, thank you !
    – Nathan
    May 9, 2022 at 13:32

Lots of pallets have this, for example Collective. It represents "instance" and means the pallet can exist multiple times within a runtime with different configs.

Collective is indeed used twice in Polkadot, once for the Council, and again for the Technical Committee

pub type CouncilCollective = pallet_collective::Instance1;
impl pallet_collective::Config<CouncilCollective> for Runtime {
    type Origin = Origin;
    type Proposal = Call;
    type Event = Event;
    type MotionDuration = CouncilMotionDuration;
    type MaxProposals = CouncilMaxProposals;
    type MaxMembers = CouncilMaxMembers;
    type DefaultVote = pallet_collective::PrimeDefaultVote;
    type WeightInfo = weights::pallet_collective_council::WeightInfo<Runtime>;

pub type TechnicalCollective = pallet_collective::Instance2;
impl pallet_collective::Config<TechnicalCollective> for Runtime {
    type Origin = Origin;
    type Proposal = Call;
    type Event = Event;
    type MotionDuration = TechnicalMotionDuration;
    type MaxProposals = TechnicalMaxProposals;
    type MaxMembers = TechnicalMaxMembers;
    type DefaultVote = pallet_collective::PrimeDefaultVote;
    type WeightInfo = weights::pallet_collective_technical_committee::WeightInfo<Runtime>;
  • Oooooh, i understand ! But why is there a need for a generic parameter within the pallet ? Is this a substrate syntax, or is it some rust dark magic ?
    – Nathan
    May 9, 2022 at 9:22
  • I'm guessing the FRAME macros that expand the pallet code into the runtime Wasm need the generic parameter, but would need one of the FRAME core guys like @shawntabrizi to help out more. May 9, 2022 at 9:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.