Dependency Management
This document defines the recommended practices for managing dependencies in JavaScript/TypeScript projects across Decentraland's ecosystem. It applies to front-end, back-end, SDKs, shared libraries, and any npm/yarn/pnpm-based package.
TL;DR:
Version strategy → Use exact/fixed versions for
dependencies(security) anddevDependencies(consistent dev environment). Use version ranges only forpeerDependencies(flexibility).Exception → Decentraland packages (
@dcl/*,decentraland-*) can use version ranges (^) as they are trusted internal packages.Libraries/shared packages → Use
peerDependencieswith version ranges (^) for shared libraries (React, @dcl/schemas, etc.). Usedependencieswith exact versions only for utilities safe to duplicate.Apps/final services → Use
dependencieswith exact versions for runtime packages (React, ethers, etc.).
1. Rationale
Many libraries rely on global singletons, React Context, class identity, shared caches, schema enums, or shared DB pools. Installing multiple versions of the same library can cause:
Context not shared between copies
Duplicate caches or pools
Failing instanceof checks
Enum/symbol mismatches
Increased bundle size
Hard-to-diagnose runtime bugs
Correct dependency management prevents these issues.
Non-goals
This standard does not attempt to:
Enforce a single package manager (npm, yarn, pnpm are all supported)
Guarantee a single physical copy in
node_modules(focus is on runtime/bundle deduplication)
2. Definitions
dependencies
Packages used internally by the module
None - consumer is not expected to provide them
Apps and libraries
peerDependencies
Packages that must resolve to a single effective version at runtime
Must install them (or use peerDependenciesMeta for optional)
Libraries only
peerDependenciesMeta
Metadata for peerDependencies, used to mark peers as optional
None - only affects package manager behavior
Libraries only
devDependencies
Tooling only used during development
None
Apps and libraries
About peerDependenciesMeta
peerDependenciesMeta is a field that provides metadata about your peerDependencies. The most common use case is marking peers as optional:
Required peers (default): Package manager will warn if not installed
Optional peers: Package manager won't warn if missing; your package should handle their absence gracefully
This is useful for packages that can work with or without certain dependencies (e.g., a utility that works with or without React, or a library that supports multiple Web3 providers).
Apps vs Libraries
Libraries / Shared Packages:
Use
peerDependenciesfor packages that must resolve to a single effective version at runtime (React, ethers, @dcl/schemas)Consumer (app) provides these dependencies
Prevents duplicate installations and singleton conflicts
Apps / Final Services:
Often use
dependenciesfor runtime packages (React, ethers, etc.)They are the final consumer, so duplication is not a concern
peerDependenciesstill valid if the app might be consumed as a dependency
3. When to Use Each Field
Quick reference: See Section 4 for common packages and their recommended placement.
Use peerDependencies for (Libraries only):
In shared libraries/packages, use peerDependencies for packages that must resolve to a single effective version at runtime:
React, Redux, wagmi, ethers, viem
@dcl/schemas and similar cross-ecosystem libraries
decentraland/connect
DB drivers when sharing pools
Any library relying on singletons or context
✅ Correct (Library):
❌ Incorrect (Library using dependencies for shared libs):
Use dependencies for:
Utilities safe to duplicate (lodash-es, date-fns)
In apps: Runtime packages like React, ethers (when app is final consumer)
Important: Always use exact/fixed versions in
dependenciesfor security.
✅ Correct (Library):
✅ Correct (App):
Optional peerDependencies (peerDependenciesMeta)
For reusable packages that work with or without certain dependencies, use peerDependenciesMeta to mark peers as optional:
✅ Correct:
What this means:
reactis required: Consumer must install it or package manager will warnethersis optional: Consumer doesn't need to install it; your package should check for its presence before using it
Use cases:
Packages that work in both React and non-React environments
Libraries that support multiple Web3 providers (ethers, viem, etc.)
Utilities that enhance other libraries but aren't required
Use devDependencies for:
Tooling (TypeScript, ESLint, testers, bundlers)
Important: Always use exact/fixed versions in
devDependenciesto ensure a consistent development environment across the team.
✅ Correct:
4. Examples
Packages that MUST be peerDependencies (shared context / singletons)
react,react-dom,react-redux,react-router-domredux,@reduxjs/toolkitethers,viem,wagmi@dcl/schemas,@dcl/ui-env,@dcl/cryptodecentraland-dapps,decentraland-ui,decentraland-ui2,decentraland-connectpg,pg-pool
Packages that SHOULD be dependencies (safe to duplicate)
lodash-es,date-fnsuuid,nanoidzod,ajvms,mitt,fp-future
5. Related Standards
Last updated