What is Metro?
metro finds Discord’s internal modules for you. It walks the module registry and returns the module that matches the description you give it.
Discord’s mobile app is a React Native bundle: thousands of Metro modules packed into one file. Nothing is global. Every store, component, and helper sits behind an opaque numeric module id, so before you can change a behavior you have to find the module that owns it.
Other parts of the API depend on Metro too. assets, i18n, the common handles, flux stores, and your own addons all use it to locate modules.
Learn this module first. The search patterns on this page come up throughout the rest of the API.
Finding modules
EachfindBy* helper matches a module by one kind of identifying trait, such as its properties, its name, or its prototype. You rarely know a module’s id, but you usually know one of these.
- By props
- By name
- By store
Match a module by the properties it exposes. This is the most common search.
On mobile, use
findByName for components, since most are identified by their name. findByDisplayName covers components that set a displayName, which is less common on mobile than on desktop.Filters
A filter is a predicate that returnstrue for the module you want. Every findBy* helper is a shortcut for a filter.
Filters live on metro.filters. If the built-in helpers don’t fit the shape you need, build your own filter and pass it to find (or findLazy).
Lazy resolution & caching
Metro keeps startup fast in two ways: it caches search results, and it can defer a search until you use the result. Every filter has a cache key, so Metro remembers a successful search. The next search for the same shape resolves from the cache instead of walking the registry. To defer a search, pass{ lazy: true }. You get a proxy back, and the search runs the first time you access it. A module referenced at the top of a file but used only inside a rarely called function costs nothing until that function runs.
Use lazy resolution for module handles declared at module scope. This is how Unbound references dozens of modules without paying for all of them at launch.
Caching custom filters
ThefindBy* helpers build their cache key by serializing their arguments, so their results are remembered across cold starts. A filter function you write yourself has no key, so Metro can’t cache it. Every cold start re-runs your predicate against the whole registry, which makes it the one kind of search that stays slow.
To fix this, wrap your filter in createCacheable and pass a second function that serializes the filter’s arguments into a key. Metro then caches the result under that key, the same way it does for a built-in filter.
Common modules & stores
Metro pre-resolves the modules most addons need: React, React Native, the dispatcher, constants, and the main flux stores. Use these instead of searching for them again.metro.stores: flux stores
metro.stores: flux stores
Pre-resolved flux stores such as
Users, Guilds, and Theme.metro.api: request helpers
metro.api: request helpers
Action-creator modules such as
Messages, Linking, and Profiles, used to trigger actions in the app.