Additionally, how does this standard handle upgrades when new facets are added to a diamond?
Regarding upgrades and new facets
Under ERC-8110, upgrade behavior depends on what the functions inside a facet require, rather than on the facet itself.
Case 1: No new storage variables required
If a facet does not contain any functions that require new storage variables:
- The facet can be placed under the appropriate existing domain.
- A regular upgrade is sufficient.
- No storage changes are required.
This is the simplest and safest upgrade path.
Case 2: Functions introduce a new domain (horizontal upgrade)
If a facet contains functions that require state which does not logically belong to any existing domain:
- This is treated as a horizontal upgrade.
- A new domain must be defined, including:
- A dedicated directory
- A new ERC-8042 storage identifier
- A new storage layout
- The facet is placed under that domain and added as part of the upgrade.
This allows new features to be introduced without impacting existing domains or storage layouts.
Case 3: Layout-breaking storage changes
If a facet contains functions that require a layout-breaking change to an existing domain’s storage
(for example: changing the inner struct of nested structs or struct arrays):
- A new, versioned storage identifier must be introduced (for example
v2).
- A new storage layout is defined under that identifier.
- Any required data migration must be handled explicitly by the project.
ERC-8110 does not attempt to automate or abstract storage migrations.
The goal is to keep schema changes intentional, visible, and auditable.
Case 4: New variables added to an existing domain (vertical upgrade)
If a facet contains functions that require additional variables which can be safely appended to the end of an existing storage layout (no layout break), this becomes a design trade-off.
There are two possible approaches, depending on the project and the team:
Option A — Evolve the existing domain
- Append new variables to the end of the existing storage struct.
- Add the new facet and selectors.
- This keeps the domain unified and works well for complex or tightly coupled business logic.
- It requires developers to carefully follow storage layout rules.
This approach allows the storage struct to evolve natively together with the domain boundary, preserving a single, cohesive domain over time.
Option B — Split into a sub-domain
- Treat the new functionality as a sub-domain of the existing domain.
- If the main domain uses the minimal identifier format:
{project}.{domain}.{version}
- The sub-domain can be defined as:
{project}.{domain}.{version}.{sub-domain}
- The sub-domain storage should contain only the new variables introduced by the new functions, leaving the original domain layout untouched.
This approach is safer and reduces cognitive load, since it avoids relying on strict append-only discipline for the original storage layout.
The trade-off is additional domain entries and higher maintenance overhead.
- This approach can be considered when a layout-breaking change (Case 3) is partial and can be cleanly isolated from the original domain.
Which option to choose depends on the project’s complexity, the team’s discipline, and long-term maintenance goals.