Getting Started

Migrating from Vue Email

Step-by-step guide to migrate your existing Vue Email project to Nuxt Email Renderer.

Learn how to migrate your existing Vue Email project to Nuxt Email Renderer. This guide covers all the steps needed to transition smoothly while maintaining your existing email templates and functionality.

Why Migrate?

Unfortunately, Vue Email is no longer actively maintained as of September, 2025.

Nuxt Email Renderer offers several advantages over Vue Email:

  • Native Nuxt 4+ Integration - Built specifically for Nuxt applications
  • Better DevTools Support - Visual email template preview and debugging
  • Simplified API - Server-side rendering endpoints built-in
  • TypeScript First - Full TypeScript support out of the box
  • Hot Module Replacement - Instant template updates during development
This module does not provide the EMarkdown and ETailwind components available in Vue Email. They are also not part of the roadmap for future development because they require significant additional code and maintenance. Consider using alternative approaches for markdown rendering and utility-first CSS in your email templates.

Migration Steps

Step 1: Remove Vue Email Dependencies

Remove the existing Vue Email packages from your project:

npm uninstall @vue-email/components @vue-email/render

Step 2: Install Nuxt Email Renderer

Install the Nuxt Email Renderer module:

npm install nuxt-email-renderer

Add the module to your nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ["nuxt-email-renderer"],
});

For detailed installation instructions, see the Installation Guide.

Step 3: Move Email Templates

Move all your email templates to the /emails directory in your project root:

Before (Vue Email):

your-project/
├── src/
│   └── emails/
│       ├── WelcomeEmail.vue
│       └── ResetPasswordEmail.vue
└── package.json

After (Nuxt Email Renderer):

your-project/
├── emails/           # 📧 Moved to root
│   ├── WelcomeEmail.vue
│   └── ResetPasswordEmail.vue
├── nuxt.config.ts
└── package.json

If you prefer to keep your templates in a different location, configure the emails directory:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ["nuxt-email-renderer"],
  
  nuxtEmailRenderer: {
    emailsDir: "/src/emails", // Custom directory
  },
});

Step 4: Update Template Imports

Update your email templates to use Nuxt Email Renderer components:

Before (Vue Email):

emails/WelcomeEmail.vue
<template>
  <Html>
    <Head />
    <Body>
      <Container>
        <Heading>Welcome {{ userName }}!</Heading>
        <Text>Thank you for joining us.</Text>
        <Button :href="confirmUrl">Confirm Account</Button>
      </Container>
    </Body>
  </Html>
</template>

<script setup>
import { Html, Head, Body, Container, Heading, Text, Button } from '@vue-email/components'

interface Props {
  userName: string
  confirmUrl: string
}

defineProps<Props>()
</script>

After (Nuxt Email Renderer):

emails/WelcomeEmail.vue
<template>
  <EHtml>
    <EHead />
    <EBody>
      <EContainer>
        <EHeading>Welcome {{ userName }}!</EHeading>
        <EText>Thank you for joining us.</EText>
        <EButton :href="confirmUrl">Confirm Account</EButton>
      </EContainer>
    </EBody>
  </EHtml>
</template>

<script setup lang="ts">
// No imports needed - components are auto-imported!

interface Props {
  userName: string
  confirmUrl: string
}

defineProps<Props>()
</script>

Component Mapping

Here's how Vue Email components map to Nuxt Email Renderer components:

Vue EmailNuxt Email RendererNotes
<Html><EHtml>Same functionality
<Head><EHead>Same functionality
<Body><EBody>Same functionality
<Container><EContainer>Same functionality
<Text><EText>Same functionality
<Heading><EHeading>Same functionality
<Button><EButton>Same functionality
<Img><EImg>Same functionality
<Link><ELink>Same functionality
<Hr><EHr>Same functionality
<Section><ESection>Same functionality
<Row><ERow>Same functionality
<Column><EColumn>Same functionality
<CodeBlock><ECodeBlock>Same functionality
<CodeInline><ECodeInline>Same functionality
<Font><EFont>Same functionality
<Preview><EPreview>Same functionality
<Style><EStyle>Same functionality
<EMarkdown>Not implemented
<ETailwind>Not implemented

Step 5: Update Rendering Logic

Replace your Vue Email rendering code with Nuxt Email Renderer API calls:

Before (Vue Email):

import { render } from '@vue-email/render'
import WelcomeEmail from './emails/WelcomeEmail.vue'

const html = await render(WelcomeEmail, {
  userName: 'John Doe',
  confirmUrl: 'https://example.com/confirm'
})

After (Nuxt Email Renderer):

// Use the built-in API endpoint
const html = await $fetch('/api/emails/render', {
  method: 'POST',
  body: {
    template: 'WelcomeEmail',
    props: {
      userName: 'John Doe',
      confirmUrl: 'https://example.com/confirm'
    }
  }
})

Verification

After migration, verify everything works:

  1. Start your development server:
    npm run dev
    
  2. Check Nuxt DevTools:
    • Open your browser's DevTools
    • Navigate to the "Nuxt Email Renderer" tab
    • Verify your templates are listed
  3. Test rendering:
    curl -X POST http://localhost:3000/api/emails/render \
      -H "Content-Type: application/json" \
      -d '{"template":"WelcomeEmail","props":{"userName":"Test","confirmUrl":"https://example.com"}}'
    

Common Migration Issues

Template Not Found

Problem: Template 'WelcomeEmail' not found

Solution:

  • Ensure templates are in the correct directory (/emails by default)
  • Check filename matches exactly (case-sensitive)
  • Verify the template file extension is .vue

Component Import Errors

Problem: Components not recognized in templates

Solution:

  • Remove manual component imports from Vue Email
  • Components are auto-imported in Nuxt Email Renderer
  • Ensure you're using the E prefix (e.g., EHtml, EBody)

Props Type Errors

Problem: TypeScript errors with template props

Solution:

  • Ensure defineProps<Props>() is used correctly
  • Add lang="ts" to your script setup block
  • Verify interface definitions match your API calls

Need Help?

If you encounter issues during migration: