or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

config-loading.mdconfig-merging.mddefault-config.mdindex.md

config-merging.mddocs/

0

# Configuration Merging

1

2

Deep merge multiple Metro configurations with validation and type safety.

3

4

## Capabilities

5

6

### Merge Configuration

7

8

Deeply merges multiple Metro configuration objects with intelligent handling of arrays, objects, and functions.

9

10

```javascript { .api }

11

/**

12

* Deep merges multiple Metro configuration objects

13

* @param defaultConfig - Base configuration object

14

* @param configs - Additional configurations to merge (later configs take precedence)

15

* @returns Complete merged Metro configuration

16

*/

17

function mergeConfig<T: $ReadOnly<InputConfigT>>(

18

defaultConfig: T,

19

...configs: Array<InputConfigT>

20

): T;

21

```

22

23

**Usage Examples:**

24

25

```javascript

26

import { getDefaultConfig, loadConfig, mergeConfig } from "metro-config";

27

28

// Merge user config with defaults

29

const defaultConfig = await getDefaultConfig();

30

const userConfig = await loadConfig();

31

const finalConfig = mergeConfig(defaultConfig, userConfig);

32

33

// Merge multiple configurations

34

const baseConfig = {

35

resolver: {

36

sourceExts: ['js', 'jsx'],

37

platforms: ['ios', 'android']

38

},

39

server: {

40

port: 8081

41

}

42

};

43

44

const platformConfig = {

45

resolver: {

46

sourceExts: ['js', 'jsx', 'ts', 'tsx'], // Replaces array

47

assetExts: ['png', 'jpg'] // Adds new property

48

}

49

};

50

51

const customConfig = {

52

transformer: {

53

babelTransformerPath: 'custom-transformer'

54

}

55

};

56

57

// Merge multiple configs - later configs take precedence

58

const merged = mergeConfig(baseConfig, platformConfig, customConfig);

59

// Result:

60

// {

61

// resolver: {

62

// sourceExts: ['js', 'jsx', 'ts', 'tsx'],

63

// platforms: ['ios', 'android'],

64

// assetExts: ['png', 'jpg']

65

// },

66

// server: {

67

// port: 8081

68

// },

69

// transformer: {

70

// babelTransformerPath: 'custom-transformer'

71

// }

72

// }

73

```

74

75

## Merge Behavior

76

77

### Object Properties

78

79

Objects are deeply merged, with properties from the second config taking precedence:

80

81

```javascript

82

const config1 = {

83

resolver: {

84

sourceExts: ['js'],

85

platforms: ['ios'],

86

blockList: /node_modules/

87

}

88

};

89

90

const config2 = {

91

resolver: {

92

sourceExts: ['js', 'ts'], // Overrides

93

assetExts: ['png'] // Adds new property

94

// platforms and blockList preserved from config1

95

}

96

};

97

98

const merged = mergeConfig(config1, config2);

99

// resolver.sourceExts = ['js', 'ts']

100

// resolver.platforms = ['ios'] (preserved)

101

// resolver.assetExts = ['png'] (added)

102

// resolver.blockList = /node_modules/ (preserved)

103

```

104

105

### Array Properties

106

107

Arrays from the second configuration completely replace arrays from the first:

108

109

```javascript

110

const config1 = {

111

resolver: {

112

sourceExts: ['js', 'jsx']

113

}

114

};

115

116

const config2 = {

117

resolver: {

118

sourceExts: ['ts', 'tsx'] // Completely replaces

119

}

120

};

121

122

const merged = mergeConfig(config1, config2);

123

// resolver.sourceExts = ['ts', 'tsx'] (not merged)

124

```

125

126

### Function Properties

127

128

Functions from the second configuration replace functions from the first:

129

130

```javascript

131

const config1 = {

132

transformer: {

133

getTransformOptions: async () => ({

134

transform: { inlineRequires: false }

135

})

136

}

137

};

138

139

const config2 = {

140

transformer: {

141

getTransformOptions: async () => ({

142

transform: { inlineRequires: true }

143

})

144

}

145

};

146

147

const merged = mergeConfig(config1, config2);

148

// Uses config2's getTransformOptions function

149

```

150

151

### Primitive Properties

152

153

Primitive values (strings, numbers, booleans) from the second config override the first:

154

155

```javascript

156

const config1 = {

157

server: {

158

port: 8081,

159

forwardClientLogs: false

160

}

161

};

162

163

const config2 = {

164

server: {

165

port: 3000 // Overrides

166

// forwardClientLogs preserved from config1

167

}

168

};

169

170

const merged = mergeConfig(config1, config2);

171

// server.port = 3000

172

// server.forwardClientLogs = false (preserved)

173

```

174

175

## Advanced Merging Patterns

176

177

### Extending Array Configuration

178

179

To extend rather than replace arrays, pre-process your configuration:

180

181

```javascript

182

import { getDefaultConfig, mergeConfig } from "metro-config";

183

184

async function createExtendedConfig(userConfig) {

185

const defaultConfig = await getDefaultConfig();

186

187

// Extend sourceExts rather than replace

188

const extendedConfig = {

189

...userConfig,

190

resolver: {

191

...userConfig.resolver,

192

sourceExts: [

193

...defaultConfig.resolver.sourceExts,

194

...(userConfig.resolver?.sourceExts || [])

195

]

196

}

197

};

198

199

return mergeConfig(defaultConfig, extendedConfig);

200

}

201

```

202

203

### Conditional Configuration Merging

204

205

Handle environment-specific configurations:

206

207

```javascript

208

import { getDefaultConfig, mergeConfig } from "metro-config";

209

210

async function createConfig() {

211

const baseConfig = await getDefaultConfig();

212

213

const developmentConfig = {

214

server: {

215

port: 8081,

216

forwardClientLogs: true

217

},

218

resetCache: true

219

};

220

221

const productionConfig = {

222

transformer: {

223

minifierPath: 'metro-minify-terser',

224

minifierConfig: {

225

mangle: { toplevel: true },

226

compress: { drop_console: true }

227

}

228

}

229

};

230

231

const envConfig = process.env.NODE_ENV === 'production'

232

? productionConfig

233

: developmentConfig;

234

235

return mergeConfig(baseConfig, envConfig);

236

}

237

```

238

239

### Function Configuration Merging

240

241

Compose transform functions when merging:

242

243

```javascript

244

const baseConfig = {

245

transformer: {

246

getTransformOptions: async (entryPoints, options) => ({

247

transform: {

248

experimentalImportSupport: false,

249

inlineRequires: false

250

}

251

})

252

}

253

};

254

255

const enhancedConfig = {

256

transformer: {

257

getTransformOptions: async (entryPoints, options) => {

258

// Get base transform options

259

const baseTransform = await baseConfig.transformer.getTransformOptions(

260

entryPoints,

261

options

262

);

263

264

// Enhance with additional options

265

return {

266

...baseTransform,

267

transform: {

268

...baseTransform.transform,

269

inlineRequires: true // Override specific option

270

},

271

preloadedModules: false

272

};

273

}

274

}

275

};

276

277

const merged = mergeConfig(baseConfig, enhancedConfig);

278

```

279

280

## Validation After Merging

281

282

The merged configuration is automatically validated:

283

284

```javascript

285

import { mergeConfig } from "metro-config";

286

287

try {

288

const merged = mergeConfig(config1, config2);

289

// Configuration is valid and ready to use

290

} catch (error) {

291

if (error.name === 'ValidationError') {

292

console.error('Merged configuration is invalid:', error.message);

293

// Handle validation errors

294

}

295

}

296

```

297

298

## Type Safety

299

300

When using TypeScript, the merge function provides type safety:

301

302

```typescript

303

import type { InputConfigT } from 'metro-config';

304

import { mergeConfig } from 'metro-config';

305

306

const config1: InputConfigT = {

307

resolver: {

308

sourceExts: ['js', 'jsx']

309

}

310

};

311

312

const config2: InputConfigT = {

313

resolver: {

314

sourceExts: ['ts', 'tsx'],

315

// TypeScript ensures all properties are valid

316

}

317

};

318

319

const merged = mergeConfig(config1, config2);

320

// merged has complete ConfigT type

321

```