Files
stack/packages/mosaic/framework/skills/nuxt/references/advanced-hooks.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
2026-08-19 14:37:17 -05:00

6.5 KiB

name, description
name description
lifecycle-hooks Nuxt and Nitro hooks for extending build-time and runtime behavior

Lifecycle Hooks

Nuxt provides hooks to tap into the build process, application lifecycle, and server runtime.

Build-time Hooks (Nuxt)

Used in nuxt.config.ts or modules:

In nuxt.config.ts

// nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'build:before': () => {
      console.log('Build starting...');
    },
    'pages:extend': (pages) => {
      // Add custom pages
      pages.push({
        name: 'custom',
        path: '/custom',
        file: '~/pages/custom.vue',
      });
    },
    'components:dirs': (dirs) => {
      // Add component directories
      dirs.push({ path: '~/extra-components' });
    },
  },
});

In Modules

// modules/my-module.ts
export default defineNuxtModule({
  setup(options, nuxt) {
    nuxt.hook('ready', async (nuxt) => {
      console.log('Nuxt is ready');
    });

    nuxt.hook('close', async (nuxt) => {
      console.log('Nuxt is closing');
    });

    nuxt.hook('modules:done', () => {
      console.log('All modules loaded');
    });
  },
});

Common Build Hooks

Hook When
ready Nuxt initialization complete
close Nuxt is closing
modules:done All modules installed
build:before Before build starts
build:done Build complete
pages:extend Pages routes resolved
components:dirs Component dirs being resolved
imports:extend Auto-imports being resolved
nitro:config Before Nitro config finalized
vite:extend Vite context created
vite:extendConfig Before Vite config finalized

App Hooks (Runtime)

Used in plugins and composables:

In Plugins

// plugins/lifecycle.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('app:created', (vueApp) => {
    console.log('Vue app created');
  });

  nuxtApp.hook('app:mounted', (vueApp) => {
    console.log('App mounted');
  });

  nuxtApp.hook('page:start', () => {
    console.log('Page navigation starting');
  });

  nuxtApp.hook('page:finish', () => {
    console.log('Page navigation finished');
  });

  nuxtApp.hook('page:loading:start', () => {
    console.log('Page loading started');
  });

  nuxtApp.hook('page:loading:end', () => {
    console.log('Page loading ended');
  });
});

Common App Hooks

Hook When
app:created Vue app created
app:mounted Vue app mounted (client only)
app:error Fatal error occurred
page:start Page navigation starting
page:finish Page navigation finished
page:loading:start Loading indicator should show
page:loading:end Loading indicator should hide
link:prefetch Link is being prefetched

Using Runtime Hooks

// composables/usePageTracking.ts
export function usePageTracking() {
  const nuxtApp = useNuxtApp();

  nuxtApp.hook('page:finish', () => {
    trackPageView(useRoute().path);
  });
}

Server Hooks (Nitro)

Used in server plugins:

// server/plugins/hooks.ts
export default defineNitroPlugin((nitroApp) => {
  // Modify HTML before sending
  nitroApp.hooks.hook('render:html', (html, { event }) => {
    html.head.push('<meta name="custom" content="value">');
    html.bodyAppend.push('<script>console.log("injected")</script>');
  });

  // Modify response
  nitroApp.hooks.hook('render:response', (response, { event }) => {
    console.log('Sending response:', response.statusCode);
  });

  // Before request
  nitroApp.hooks.hook('request', (event) => {
    console.log('Request:', event.path);
  });

  // After response
  nitroApp.hooks.hook('afterResponse', (event) => {
    console.log('Response sent');
  });
});

Common Nitro Hooks

Hook When
request Request received
beforeResponse Before sending response
afterResponse After response sent
render:html Before HTML is sent
render:response Before response is finalized
error Error occurred

Custom Hooks

Define Custom Hook Types

// types/hooks.d.ts
import type { HookResult } from '@nuxt/schema';

declare module '#app' {
  interface RuntimeNuxtHooks {
    'my-app:event': (data: MyEventData) => HookResult;
  }
}

declare module '@nuxt/schema' {
  interface NuxtHooks {
    'my-module:init': () => HookResult;
  }
}

declare module 'nitropack/types' {
  interface NitroRuntimeHooks {
    'my-server:event': (data: any) => void;
  }
}

Call Custom Hooks

// In a plugin
export default defineNuxtPlugin((nuxtApp) => {
  // Call custom hook
  nuxtApp.callHook('my-app:event', { type: 'custom' });
});

// In a module
export default defineNuxtModule({
  setup(options, nuxt) {
    nuxt.callHook('my-module:init');
  },
});

useRuntimeHook

Call hooks at runtime from components:

<script setup lang="ts">
// Register a callback for a runtime hook
useRuntimeHook('app:error', (error) => {
  console.error('App error:', error);
});
</script>

Hook Examples

Page View Tracking

// plugins/analytics.client.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('page:finish', () => {
    const route = useRoute();
    analytics.track('pageview', {
      path: route.path,
      title: document.title,
    });
  });
});

Performance Monitoring

// plugins/performance.client.ts
export default defineNuxtPlugin((nuxtApp) => {
  let navigationStart: number;

  nuxtApp.hook('page:start', () => {
    navigationStart = performance.now();
  });

  nuxtApp.hook('page:finish', () => {
    const duration = performance.now() - navigationStart;
    console.log(`Navigation took ${duration}ms`);
  });
});

Inject HTML

// server/plugins/inject.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('render:html', (html) => {
    html.head.push(`
      <script>
        window.APP_CONFIG = ${JSON.stringify(config)}
      </script>
    `);
  });
});