Configuring Metro
A Metro config can be created in these three ways (ordered by priority):
metro.config.js
metro.config.json
- The
metro
field inpackage.json
You can also give a custom file to the configuration by specifying --config <path/to/config>
when calling the CLI.
When Metro is started via the React Native CLI, some defaults are different from those mentioned below. See the React Native repository for details.
Configuration Structureβ
The configuration is based on our concepts, which means that for every module we have a separate config option. A common configuration structure in Metro looks like this:
module.exports = {
/* general options */
resolver: {
/* resolver options */
},
transformer: {
/* transformer options */
},
serializer: {
/* serializer options */
},
server: {
/* server options */
},
watcher: {
/* watcher options */
watchman: {
/* Watchman-specific options */
}
}
};
General Optionsβ
cacheStores
β
Type: CacheStores
(see details below)
A list of storage adapters for Metro's transformer cache. This can be any combination of built-in cache stores and custom cache stores. Defaults to using a temporary directory on disk as the only cache store.
When Metro needs to transform a module, it first computes a machine-independent cache key for that file, and uses it to try to read from each of the stores in order. Once Metro has obtained the output of the transformer (whether already cached or not), it writes the transform result to all of the stores that returned null
(a cache miss) for that key.
type CacheStores =
| Array<CacheStore<Buffer | JsonSerializable>>
| ((MetroCache) => Array<
CacheStore<Buffer | JsonSerializable>
>);
// The exports of 'metro-cache'
type MetroCache = {
FileStore,
AutoCleanFileStore,
HttpStore,
HttpGetStore,
...
};
type JsonSerializable = /* Any JSON-serializable value */;
cacheVersion
β
Type: string
An arbitrary string appended to all cache keys in the project before they are hashed. There is generally no need to set this explicitly, as Metro will automatically derive the correct cache keys from your project config and the contents of source files.
projectRoot
β
Type: string
The root folder of your project. If your project depends on any files outside this root, their containing directories must be listed in watchFolders
.
If your Metro project is developed in a monorepo and includes files from multiple logical packages, you'll generally want to set projectRoot
to the root of your repository, or at least high enough in the hierarchy that all relevant files are reachable without separately configuring watchFolders
.
watchFolders
β
Type: Array<string>
A list of directories outside of projectRoot
that can contain source files for the project.
Despite the naming of this option, it isn't related solely to file watching. Even in an offline build (for example, in CI), all files must be visible to Metro through the combination of watchFolders
and projectRoot
.
Note that, as with any other file Metro needs to resolve, targets of any symlinks within your watchFolders
must also be within watchFolders
and not otherwise excluded.
If you have a Metro project within a workspace, such as a Yarn workspace (a subdirectory of a Yarn workspace root), it's likely you'll want to include your workspace root path in your configured watchFolders
so that Metro can resolve other workspaces or hoisted node_modules
. Similarly, to use linked packages, you'll need to list those package source locations (or a containing directory) in watchFolders
.
transformerPath
β
Type: string
The absolute path of a module (or a package name resolvable from the metro
package) that implements a transformer.
See the implementation of Metro's default transformer (metro-transform-worker
) for more information about the transformer interface.
reporter
β
Type: {update: (event: ReportableEvent) => void}
Used to report the status of the bundler during the bundling process. The default implementation prints most events to the terminal.
See also the definition of ReportableEvent
in Metro's source code.
resetCache
β
Type: boolean
If true
, Metro will reset the transformer cache (see cacheStores
) and the file map cache (see fileMapCacheDirectory
) on startup.
stickyWorkers
β
Type: boolean
If true
, Metro will use a stable mapping from files to transformer workers, so the same file is always transformed by the same worker. This can improve initial build performance if the transformer is expensive to initialize, but can slow down concurrent builds with different configurations (e.g. multiple React Native apps connected to one Metro server). Defaults to true
.
maxWorkers
β
Type: number
The number of workers to use for parallel processing in Metro. Defaults to approximately half of the number of cores available on the machine, as reported by os.availableParallelism()
.
- Values exceeding the number of available cores have no effect.
- If
maxWorkers
is set to 1 or lower, worker code will run in the main Metro process instead of concurrently. - Metro has two separate worker pools - one for transformation and one for building the file map. Each pool has its worker count set to
maxWorkers
independently.
fileMapCacheDirectory
β
Type: string
The path to the metro-file-map
cache directory, defaults to os.tmpdir()
.
hasteMapCacheDirectory
Deprecatedβ
Type: string
Alias of fileMapCacheDirectory
unstable_perfLoggerFactory
β
Type: PerfLoggerFactory
A logger factory function that can be used to get insights about Metro performance timings and metadata for events including startup, bundling and HMR. Metro expects unstable_perfLoggerFactory
to have the following signature:
function unstable_perfLoggerFactory(
type: string,
opts: $ReadOnly<{
key?: string
}>,
): RootPerfLogger {
// ...
};
type
Type of event being logged, e.g.'STARTUP'
,'BUNDLING_REQUEST'
,'HMR'
. See type definition of PerfLoggerFactory for a full list of event types.opts
key
: An opaque identifier to distinguish between instances of an event type (e.g. multiple, possibly concurrent, HMR requests).
unstable_perfLoggerFactory
should return an object implementing the RootPerfLogger interface. For example, a factory function returning a no-op RootPerfLogger could be implemented as follows:
const unstable_perfLoggerFactory = (type, factoryOpts) => {
const getLogger = subSpanLabel => {
const logger = {
start(opts) {},
end(status, opts) {},
subSpan(label) {
return getLogger(`${subSpanLabel ?? ''}/${label}`);
},
point(name, opts) {},
annotate(annotations) {},
};
return logger;
};
return getLogger();
};
Resolver Optionsβ
assetExts
β
Type: Array<string>
The list of asset file extensions to include in the bundle. For example, including 'ttf'
allows Metro bundles to reference .ttf
files. This is used primarily to enable React Native's image asset support. The default list includes many common image, video and audio file extensions. See Metro's source code for the full list.
sourceExts
β
Type: Array<string>
The list of source file extensions to include in the bundle. For example, including 'ts'
allows Metro to include .ts
files in the bundle.
The order of these extensions defines the order to match files on disk. For more information, see Module Resolution.
Defaults to ['js', 'jsx', 'json', 'ts', 'tsx']
.
resolverMainFields
β
Type: Array<string>
The list of fields in package.json
that Metro will treat as describing a package's entry points. The default is ['browser', 'main']
, so the resolver will use the browser
field if it exists and main
otherwise.
Metro's default resolver processes each of these fields according to the browser
field spec, including the ability to replace and ignore specific files. For more information, see Module Resolution.
When using React Native, resolverMainFields
defaults to ['react-native', 'browser', 'main']
.
disableHierarchicalLookup
β
Type: boolean
Whether to disable looking up modules in node_modules
folders. This only affects the default search through the directory tree, not other Metro options like extraNodeModules
or nodeModulesPaths
. Defaults to false
.
emptyModulePath
β
Type: string
What module to use as the canonical "empty" module when one is needed. Defaults to using the one included in metro-runtime
. You only need to change this if Metro is installed outside of your project.
enableGlobalPackages
β
Type: boolean
.
Whether to automatically resolve references to first-party packages (e.g. workspaces) in your project. Any package.json
file with a valid name
property within projectRoot
or watchFolders
(but outside of node_modules
) counts as a package for this purpose. Defaults to false
.
extraNodeModules
β
Type: {[string]: string}
A mapping of package names to directories that is consulted after the standard lookup through node_modules
as well as any nodeModulesPaths
. For more information, see Module Resolution.
nodeModulesPaths
β
Type: Array<string>
A list of paths to check for modules after looking through all node_modules
directories. This is useful if third-party dependencies are installed in a different location outside of the direct path of source files. For more information, see Module Resolution.
resolveRequest
β
Type: ?CustomResolver
An optional function used to override the default resolution algorithm. This is particularly useful for cases where aliases or custom protocols are used. For example:
resolveRequest: (context, moduleName, platform) => {
if (moduleName.startsWith('my-custom-resolver:')) {
// Logic to resolve the module name to a file path...
// NOTE: Throw an error if there is no resolution.
return {
filePath: 'path/to/file',
type: 'sourceFile',
};
}
// Optionally, chain to the standard Metro resolver.
return context.resolveRequest(context, moduleName, platform);
}
For more information on customizing the resolver, see Module Resolution.
useWatchman
β
Type: boolean
If set to false
, prevents Metro from using Watchman (even if it's installed).
blockList
β
Type: RegExp
or Array<RegExp>
A regular expression (or list of regular expressions) defining which paths to exclude from Metro's file map. Files whose absolute paths match these patterns are effectively hidden from Metro and cannot be resolved or imported in the current project.
hasteImplModulePath
β
Type: ?string
The path to the Haste implementation for the current project. Haste is an opt-in mechanism for importing modules by their globally-unique name anywhere in the project, e.g. import Foo from 'Foo'
.
Metro expects this module to have the following signature:
module.exports = {
getHasteName(filePath: string): ?string {
// ...
},
};
getHasteName
should return a short, globally unique name for the module whose path is filePath
, or null
if the module should not be accessible via Haste.
platforms
β
Type: Array<string>
Additional platforms to resolve. Defaults to ['ios', 'android', 'windows', 'web']
.
For more information, see Module Resolution and React Native's documentation for platform-specific extensions.
requireCycleIgnorePatterns
β
Type: Array<RegExp>
In development mode, suppress require cycle warnings for any cycle involving a module that matches any of these expressions. This is useful for third-party code and first-party expected cycles.
Note that if you specify your own value for this config option it will replace (not concatenate with) Metro's default.
Defaults to [/(^|\/|\\)node_modules($|\/|\\)/]
.
unstable_conditionNames
Experimentalβ
Type: Array<string>
This setting will take effect when unstable_enablePackageExports
is true
. It may not behave as described while this feature is experimental.
The set of condition names to assert globally when interpreting the "exports"
field in package.json.
Conditions may be any string value and are resolved in the order specified by each package. Node.js documents a number of community conditions which are commonly used by package authors. The default
condition is always matched.
Defaults to ['require']
.
When using React Native, unstable_conditionNames
defaults to ['require', 'react-native']
.
unstable_conditionsByPlatform
Experimentalβ
Type: {[platform: string]: Array<string>}
This setting will take effect when unstable_enablePackageExports
is true
. It may not behave as described while this feature is experimental.
The set of additional condition names to dynamically assert by platform (see platforms
) when interpreting the "exports"
field in package.json.
Matched conditions are merged with unstable_conditionNames
before resolution. With the defaults for both options, the conditions new Set(['require', 'browser'])
will be asserted when requesting a web
bundle, and new Set(['require'])
otherwise. Again, these are resolved in the order specified by each package.
Defaults to β{ web: ['browser'] }
.
unstable_enablePackageExports
Experimentalβ
Type: boolean
Enable experimental Package Exports support. Under this mode, Metro will read the "exports"
field in package.json
files when present and use it to resolve package entry points.
When no match is found in "exports"
, Metro will log a warning and fall back to resolving modules without considering "exports"
. This makes this mode largely backwards-compatible, with the following exceptions:
- If a module is matched in
"exports"
,sourceExts
andplatforms
will not be considered (i.e. platform-specific extensions will not be used). This is done for compatibility with Node. - If a module exists at a file path that is also listed in
"exports"
, and the"exports"
entry maps to a different file, the"exports"
entry will be preferred.
Defaults to false
.
In a future release of Metro, this option will become true
by default.
Transformer Optionsβ
asyncRequireModulePath
Deprecatedβ
Type: string
The name of a module that provides the asyncRequire
function, which is used to implement dynamic import()
at runtime. Defaults to metro-runtime/src/modules/asyncRequire
.
The module named by asyncRequireModulePath
is resolved relative to the module containing the original import()
call. In particular, assuming the default value of asyncRequireModulePath
is in use, the project must have a compatible version of metro-runtime
installed in node_modules
.
In older versions of Metro, a custom asyncRequireModulePath
could be used as part of a bundle splitting solution. This usage is now deprecated in favor of the __loadBundleAsync
API.
dynamicDepsInPackages
β
Type: 'throwAtRuntime' | 'reject'
Controls how Metro handles dependencies that cannot be statically analyzed at build time. For example, require('./' + someFunction() + '.js')
cannot be resolved without knowing what someFunction()
will return.
'throwAtRuntime'
(the default): Metro does not stop bundling, but therequire
call will throw at runtime.'reject'
: Metro will stop bundling and report an error to the user.
getTransformOptions
β
Type: Function (see details below)
A function called by Metro to calculate additional options for the transformer and serializer based on the specific bundle being built.
Metro expects getTransformOptions
to have the following signature:
function getTransformOptions(
entryPoints: $ReadOnlyArray<string>,
options: {
dev: boolean,
hot: boolean,
platform: ?string,
},
getDependenciesOf: (path: string) => Promise<Array<string>>,
): Promise<ExtraTransformOptions> {
// ...
}
getTransformOptions
receives these parameters:
entryPoints
: Absolute paths to the bundle's entry points (typically just one).options
:dev
: Whether the bundle is being built in development mode.hot
:DeprecatedAlways true.platform
: The target platform (e.g.ios
,android
).
getDependenciesOf
: A function which, given an absolute path to a module, returns a promise that resolves to the absolute paths of the module's transitive dependencies.
getTransformOptions
should return a promise that resolves to an object with the following properties:
type ExtraTransformOptions = {
preloadedModules?: {[path: string]: true} | false,
ramGroups?: Array<string>,
transform?: {
inlineRequires?: {blockList: {[string]: true}} | boolean,
nonInlinedRequires?: $ReadOnlyArray<string>,
},
};
preloadedModules
: A plain object whose keys represent a set of absolute paths. When serializing an indexed RAM bundle, the modules in this set will be marked for eager evaluation at runtime.ramGroups
: An array of absolute paths. When serializing an indexed RAM bundle, each of the listed modules will be serialized along with its transitive dependencies. At runtime, the modules will all be parsed together as soon as any one of them is evaluated.transform
: Advanced options for the transformer.inlineRequires
:- If
inlineRequires
is a boolean, it controls whether inline requires are enabled in this bundle. - If
inlineRequires
is an object, inline requires are enabled in all modules, except ones whose absolute paths appear as keys ofinlineRequires.blockList
.
- If
nonInlinedRequires
: An array of unresolved module specifiers (e.g.react
,react-native
) to never inline, even when inline requires are enabled.
minifierPath
β
Type: string
(default: 'metro-minify-terser'
)
Path, or package name resolvable from metro-transform-worker
, to the minifier that minifies the code after transformation.
minifierConfig
β
Type: {[key: string]: mixed}
Configuration object that will be passed to the minifier (it should be serializable).
optimizationSizeLimit
β
Type: number
Define a threshold (in bytes) to disable some expensive optimizations for big files.
React Native Onlyβ
assetPlugins
β
Type: Array<string>
List of modules to call to modify Asset data
assetRegistryPath
β
Type: string
Where to fetch the assets from.
Babel-specific transformer optionsβ
babelTransformerPath
β
Type: string
The name of a module that compiles code with Babel, returning an AST and optional metadata. Defaults to metro-babel-transformer
.
Refer to the source code of metro-babel-transformer
and @react-native/metro-babel-transformer
for details on implementing a custom Babel transformer.
This option only has an effect under the default transformerPath
. Custom transformers may ignore it.
enableBabelRCLookup
β
Type: boolean
Whether to enable searching for Babel configuration files. This is passed to Babel as the babelrc
config option. Defaults to true
.
This option only has an effect under the default transformerPath
. Custom transformers may ignore it. Custom Babel transformers should respect this option.
enableBabelRuntime
β
Type: boolean | string
Whether the transformer should use the @babel/transform/runtime
plugin. Defaults to true
.
If the value is a string, it is treated as a runtime version number and passed as version
to the @babel/plugin-transform-runtime
configuration. This allows you to optimize the generated Babel runtime calls based on the version installed in your project.
This option only works under the default settings for React Native. It may have no effect in a project that uses custom transformerPath
, a custom babelTransformerPath
or a custom Babel config file.
hermesParser
β
Type: boolean
Whether to use the hermes-parser
package to parse JavaScript source files, instead of Babel. Defaults to false
.
This option only has an effect under the default transformerPath
and the Babel transformers built into Metro. Custom transformers and custom Babel transformers may ignore it.
Serializer Optionsβ
getRunModuleStatement
β
Type: (number | string) => string
Specify the format of the initial require statements that are appended at the end of the bundle. By default is __r(${moduleId});
.
createModuleIdFactory
β
Type: () => (path: string) => number
Used to generate the module id for require
statements.
getPolyfills
β
Type: ({platform: ?string}) => $ReadOnlyArray<string>
An optional list of polyfills to include in the bundle. The list defaults to a set of common polyfills for Number, String, Array, Object...
getModulesRunBeforeMainModule
β
Type: (entryFilePath: string) => Array<string>
An array of modules to be required before the entry point. It should contain the absolute path of each module. Note that this will add the additional require statements only if the passed modules are already included as part of the bundle.
processModuleFilter
β
Type: (module: Array<Module>) => boolean
A filter function to discard specific modules from the output.
isThirdPartyModule
β
Type: (module: {path: string, ...}) => boolean
A function that determines which modules are added to the x_google_ignoreList
field of the source map. This supports "Just My Code" debugging in Chrome DevTools and other compatible debuggers.
Defaults to returning true
for modules with a path component named node_modules
.
In addition to modules marked as ignored by isThirdPartyModule
, Metro will also automatically add modules generated by the bundler itself to the ignore list.
Server Optionsβ
These options are used when Metro serves the content.
port
β
Type: number
Which port to listen on.
useGlobalHotkey
β
Type: boolean
Whether we should enable CMD+R hotkey for refreshing the bundle.
enhanceMiddleware
Deprecatedβ
Type: (Middleware, MetroServer) => Middleware
A function that allows attaching custom connect
middleware to Metro. For example:
You can use connect()
as a utility to extend the base metroMiddleware
and to mount additional middleware handlers.
enhanceMiddleware: (metroMiddleware: Middleware, metroServer: MetroServer) => {
return connect()
.use(metroMiddleware)
.use('/custom-endpoint', customEndpointMiddleware());
},
The Middleware
type is an alias for connect.HandleFunction
.
rewriteRequestUrl
β
Type: string => string
A function that will be called every time Metro processes a URL, after normalization of non-standard query-string delimiters using jsc-safe-url
. Metro will use the return value of this function as if it were the original URL provided by the client. This applies to all incoming HTTP requests (after any custom middleware), as well as bundle URLs in /symbolicate
request payloads and within the hot reloading protocol.
forwardClientLogs
β
Type: boolean
Enable forwarding of client_log
events (when client logs are configured) to the reporter. Defaults to true
.
Watcher Optionsβ
Options for the filesystem watcher.
Dot notation in this section indicates a nested configuration object, e.g. watchman.deferStates
β watchman: { deferStates: ... }
.
additionalExts
β
Type: Array<string>
The extensions which Metro should watch in addition to sourceExts
, but which will not be automatically tried by the resolver.
Therefore, the two behavior differences from resolver.sourceExts
when importing a module are:
- Modules can only be required when fully specified (e.g.
import moduleA from 'moduleA.mjs'
). - No platform-specific resolution is performed.
Defaults to ['cjs', 'mjs']
.
healthCheck.enabled
β
Type: boolean
Whether to periodically check the health of the filesystem watcher by writing a temporary file to the project and waiting for it to be observed.
The default value is false
.
healthCheck.filePrefix
β
Type: string
If watcher health checks are enabled, this property controls the name of the temporary file that will be written into the project filesystem.
The default value is '.metro-health-check'
.
There's no need to commit health check files to source control. If you choose to enable health checks in your project, make sure you add .metro-health-check*
to your .gitignore
file to avoid generating unnecessary changes.
healthCheck.interval
β
Type: number
If watcher health checks are enabled, this property controls how often they occur (in milliseconds).
The default value is 30000.
healthCheck.timeout
β
Type: number
If watcher health checks are enabled, this property controls the time (in milliseconds) Metro will wait for a file change to be observed before considering the check to have failed.
The default value is 5000.
watchman.deferStates
β
Type: Array<string>
Applies when using Watchman. Metro will defer processing filesystem updates while these states are asserted in the watch. This is useful for debouncing builds while the filesystem hasn't settled, e.g. during large source control operations.
The default value is ['hg.update']
.
Merging Configurationsβ
Using the metro-config
package it is possible to merge multiple configurations together.
Method | Description |
---|---|
mergeConfig(...configs): MergedConfig | Returns the merged configuration of two or more configuration objects. |
Arrays and function based config parameters do not deeply merge and will instead override any pre-existing config parameters.
This allows overriding and removing default config parameters such as platforms
or getModulesRunBeforeMainModule
that may not be required in your environment.
Merging Exampleβ
// metro.config.js
const { mergeConfig } = require('metro-config');
const configA = {
/* general options */
resolver: {
/* resolver options */
},
transformer: {
/* transformer options */
},
serializer: {
/* serializer options */
},
server: {
/* server options */
}
};
const configB = {
/* general options */
resolver: {
/* resolver options */
},
transformer: {
/* transformer options */
},
serializer: {
/* serializer options */
},
server: {
/* server options */
}
};
module.exports = mergeConfig(configA, configB);