or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compatibility.mdcomponents.mdconfiguration-types.mdcore-types.mdhooks.mdindex.mdmodules.mdruntime-config.mdschema-validation.md

modules.mddocs/

0

# Module Development

1

2

The module system in @nuxt/schema provides comprehensive type definitions for developing type-safe Nuxt modules, including module metadata, setup functions, dependency management, and compatibility checking.

3

4

## Core Module Types

5

6

### NuxtModule Interface

7

8

The main interface for creating Nuxt modules with full type safety.

9

10

```typescript { .api }

11

interface NuxtModule<

12

TOptions extends ModuleOptions = ModuleOptions,

13

TOptionsDefaults extends Partial<TOptions> = Partial<TOptions>,

14

TWith extends boolean = false,

15

> {

16

(

17

this: void,

18

resolvedOptions: TWith extends true

19

? ResolvedModuleOptions<TOptions, TOptionsDefaults>

20

: TOptions,

21

nuxt: Nuxt

22

): ModuleSetupReturn

23

24

getOptions?: (

25

inlineOptions?: Partial<TOptions>,

26

nuxt?: Nuxt

27

) => Promise<

28

TWith extends true

29

? ResolvedModuleOptions<TOptions, TOptionsDefaults>

30

: TOptions

31

>

32

33

getModuleDependencies?: (nuxt: Nuxt) => ModuleDependencies | undefined

34

}

35

36

type ModuleSetupReturn = Awaitable<false | void | ModuleSetupInstallResult>

37

type Awaitable<T> = T | Promise<T>

38

```

39

40

### ModuleMeta Interface

41

42

Metadata for module identification and compatibility.

43

44

```typescript { .api }

45

interface ModuleMeta {

46

/** Module name */

47

name?: string

48

/** Module version */

49

version?: string

50

/** Configuration key used within nuxt.config */

51

configKey?: string

52

/** Version constraints for Nuxt or features */

53

compatibility?: NuxtCompatibility

54

/** @internal Fully resolved path */

55

rawPath?: string

56

[key: string]: unknown

57

}

58

```

59

60

### Module Options and Results

61

62

```typescript { .api }

63

type ModuleOptions = Record<string, any>

64

65

type ModuleSetupInstallResult = {

66

/** Timing information for setup */

67

timings?: {

68

/** Total setup time in ms */

69

setup?: number

70

[key: string]: number | undefined

71

}

72

}

73

74

type ModuleSetupReturn = void | ModuleSetupInstallResult | Promise<void | ModuleSetupInstallResult>

75

76

interface ResolvedModuleOptions<T = ModuleOptions> {

77

src?: string

78

handler: T

79

options?: ModuleOptions

80

}

81

```

82

83

## Module Dependencies

84

85

### ModuleDependencies Interface

86

87

```typescript { .api }

88

interface ModuleDependencies {

89

[packageName: string]: ModuleDependencyMeta

90

}

91

92

interface ModuleDependencyMeta {

93

/** Dependency version requirement */

94

version?: string

95

/** Whether dependency is optional */

96

optional?: boolean

97

/** Custom installation instructions */

98

installCommand?: string

99

}

100

```

101

102

## Compatibility System

103

104

### NuxtCompatibility Interface

105

106

```typescript { .api }

107

interface NuxtCompatibility {

108

/** Required Nuxt version in semver format */

109

nuxt?: string

110

/** Builder compatibility requirements */

111

builder?: Partial<Record<'vite' | 'webpack' | 'rspack' | (string & {}), false | string>>

112

}

113

114

interface NuxtCompatibilityIssue {

115

name: string

116

message: string

117

}

118

119

interface NuxtCompatibilityIssues extends Array<NuxtCompatibilityIssue> {

120

/** Return formatted error message */

121

toString(): string

122

}

123

```

124

125

## Module Definition Patterns

126

127

### Basic Module

128

129

```typescript

130

import type { NuxtModule } from '@nuxt/schema';

131

import { defineNuxtModule } from '@nuxt/kit';

132

133

interface ModuleOptions {

134

apiKey?: string

135

timeout?: number

136

}

137

138

const myModule: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({

139

meta: {

140

name: 'my-module',

141

version: '1.0.0',

142

configKey: 'myModule',

143

compatibility: {

144

nuxt: '^3.0.0'

145

}

146

},

147

148

defaults: {

149

apiKey: '',

150

timeout: 5000

151

},

152

153

setup(options, nuxt) {

154

// Module setup logic

155

console.log('Module options:', options);

156

157

// Add runtime configuration

158

nuxt.options.runtimeConfig.myModule = {

159

apiKey: options.apiKey

160

};

161

162

// Register plugins

163

addPlugin({

164

src: path.resolve(__dirname, './runtime/plugin.client.ts'),

165

mode: 'client'

166

});

167

}

168

});

169

170

export default myModule;

171

```

172

173

### Advanced Module with Schema

174

175

```typescript

176

import type { NuxtModule } from '@nuxt/schema';

177

import { defineNuxtModule, createResolver, addImports } from '@nuxt/kit';

178

179

interface ModuleOptions {

180

enabled: boolean

181

providers: {

182

google?: {

183

clientId: string

184

clientSecret: string

185

}

186

github?: {

187

clientId: string

188

clientSecret: string

189

}

190

}

191

redirectUrl: string

192

}

193

194

const authModule: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({

195

meta: {

196

name: '@my-org/nuxt-auth',

197

version: '2.1.0',

198

configKey: 'auth',

199

compatibility: {

200

nuxt: '^3.8.0',

201

builder: {

202

vite: '^4.0.0',

203

webpack: false // Not compatible with webpack

204

}

205

}

206

},

207

208

defaults: {

209

enabled: true,

210

providers: {},

211

redirectUrl: '/auth/callback'

212

},

213

214

// JSON Schema for options validation

215

schema: {

216

type: 'object',

217

properties: {

218

enabled: { type: 'boolean' },

219

providers: {

220

type: 'object',

221

properties: {

222

google: {

223

type: 'object',

224

properties: {

225

clientId: { type: 'string' },

226

clientSecret: { type: 'string' }

227

},

228

required: ['clientId', 'clientSecret']

229

}

230

}

231

},

232

redirectUrl: { type: 'string' }

233

}

234

},

235

236

async setup(options, nuxt) {

237

if (!options.enabled) return;

238

239

const resolver = createResolver(import.meta.url);

240

241

// Add composables

242

addImports([

243

{

244

name: 'useAuth',

245

from: resolver.resolve('./runtime/composables/useAuth')

246

},

247

{

248

name: 'useAuthUser',

249

from: resolver.resolve('./runtime/composables/useAuthUser')

250

}

251

]);

252

253

// Add server middleware

254

addServerHandler({

255

route: '/api/auth/**',

256

handler: resolver.resolve('./runtime/server/auth.ts')

257

});

258

259

// Add type declarations

260

addTypeTemplate({

261

filename: 'types/auth.d.ts',

262

getContents: () => `

263

declare module '#app' {

264

interface NuxtApp {

265

$auth: {

266

user: Ref<User | null>

267

loggedIn: ComputedRef<boolean>

268

login: (provider: string) => Promise<void>

269

logout: () => Promise<void>

270

}

271

}

272

}

273

`

274

});

275

276

return {

277

timings: {

278

setup: performance.now()

279

}

280

};

281

}

282

});

283

```

284

285

### Module with Hooks

286

287

```typescript

288

const analyticsModule: NuxtModule = defineNuxtModule({

289

meta: {

290

name: 'nuxt-analytics',

291

version: '1.0.0'

292

},

293

294

hooks: {

295

'ready': async (nuxt) => {

296

console.log('Analytics module ready');

297

},

298

299

'build:before': async () => {

300

// Pre-build analytics setup

301

},

302

303

'render:route': async (url, result, context) => {

304

// Track page views

305

console.log(`Page rendered: ${url}`);

306

}

307

},

308

309

setup(options, nuxt) {

310

// Additional setup beyond hooks

311

nuxt.hook('app:resolve', async (app) => {

312

// Modify app configuration

313

app.head = app.head || {};

314

app.head.script = app.head.script || [];

315

app.head.script.push({

316

src: 'https://analytics.example.com/script.js',

317

async: true

318

});

319

});

320

}

321

});

322

```

323

324

## Module Utilities and Helpers

325

326

### Module Definition Helper

327

328

```typescript

329

function createModule<T = ModuleOptions>(

330

definition: Omit<NuxtModule<T>, 'setup'> & {

331

setup: (options: T, nuxt: Nuxt) => ModuleSetupReturn

332

}

333

): NuxtModule<T> {

334

return {

335

...definition,

336

setup: definition.setup

337

};

338

}

339

```

340

341

### Conditional Module Loading

342

343

```typescript

344

const conditionalModule: NuxtModule = defineNuxtModule({

345

meta: {

346

name: 'conditional-module'

347

},

348

349

setup(options, nuxt) {

350

// Only load in development

351

if (!nuxt.options.dev) {

352

return;

353

}

354

355

// Check for required dependencies

356

try {

357

require.resolve('some-dev-dependency');

358

} catch {

359

console.warn('Development dependency not found, skipping module');

360

return;

361

}

362

363

// Setup development features

364

addDevtools();

365

}

366

});

367

```

368

369

### Module with Runtime Dependencies

370

371

```typescript

372

interface DatabaseModuleOptions {

373

provider: 'postgres' | 'mysql' | 'sqlite'

374

connection: {

375

host?: string

376

port?: number

377

database: string

378

username?: string

379

password?: string

380

}

381

}

382

383

const databaseModule: NuxtModule<DatabaseModuleOptions> = defineNuxtModule({

384

meta: {

385

name: 'nuxt-database',

386

configKey: 'database'

387

},

388

389

async setup(options, nuxt) {

390

const resolver = createResolver(import.meta.url);

391

392

// Add required dependencies

393

await addBuildPlugin({

394

name: 'database-types',

395

setup(build) {

396

build.onResolve({ filter: /^#database$/ }, () => ({

397

path: resolver.resolve('./runtime/database'),

398

namespace: 'database'

399

}));

400

}

401

});

402

403

// Generate connection configuration

404

addTemplate({

405

filename: 'database.config.js',

406

getContents: () => `

407

export default ${JSON.stringify({

408

provider: options.provider,

409

connection: options.connection

410

}, null, 2)}

411

`

412

});

413

414

// Add database composables

415

addImports([

416

{ name: 'useDatabase', from: '#database' },

417

{ name: 'useQuery', from: '#database' }

418

]);

419

}

420

});

421

```

422

423

### Module Testing Pattern

424

425

```typescript

426

// tests/module.test.ts

427

import { describe, it, expect } from 'vitest';

428

import { setup, createPage } from '@nuxt/test-utils';

429

import type { NuxtModule } from '@nuxt/schema';

430

431

describe('My Module', async () => {

432

await setup({

433

nuxtConfig: {

434

modules: [

435

['./src/module', {

436

apiKey: 'test-key',

437

enabled: true

438

}]

439

]

440

}

441

});

442

443

it('should register composables', async () => {

444

const page = await createPage('/test');

445

446

const hasComposable = await page.evaluate(() => {

447

return typeof window.$nuxt?.$myModule !== 'undefined';

448

});

449

450

expect(hasComposable).toBe(true);

451

});

452

});

453

```

454

455

The module system provides a powerful foundation for extending Nuxt with full type safety, ensuring that modules integrate seamlessly with the Nuxt ecosystem while maintaining excellent developer experience.