How do I use React Email templates with Resend in a Node/Next.js project?
Communications APIs (CPaaS)

How do I use React Email templates with Resend in a Node/Next.js project?

10 min read

Using React Email templates with Resend in a Node or Next.js project lets you build type-safe, component-based emails that match your app’s UI and are easy to test, preview, and maintain. This guide walks through the full setup: installing dependencies, creating templates, rendering them to HTML, and sending emails via Resend in both Node.js and Next.js environments.


Why use React Email with Resend in Node/Next.js?

Before diving into the “how”, it helps to understand the “why” behind this stack:

  • React-based emails: Use JSX and components to build branded, reusable email layouts.
  • Type safety: Strong typing for template props in TypeScript projects.
  • Preview & iteration: React Email’s dev server makes quick design iterations easy.
  • Resend API: Simple, modern email API with great TypeScript support and good DX.
  • Node/Next.js friendly: Works well in backend-only Node, and in server-side Next.js routes, including App Router (app/) and Pages (pages/api/).

Prerequisites

You’ll get the most out of this tutorial if you have:

  • A Node.js or Next.js project already initialized.
  • Node.js 18+ (especially important for Next.js App Router and modern Resend SDK usage).
  • A Resend API key from resend.com.
  • Basic familiarity with:
    • React components
    • Environment variables
    • Server-side routes (Next.js API routes or Route Handlers)

Step 1: Install dependencies

In a Node/Next.js project, you’ll need:

  • react and react-dom (already included in most Next.js apps)
  • @react-email/components and optionally @react-email/render
  • resend (official Resend SDK)
# If you're in a plain Node.js project
npm install react react-dom @react-email/components @react-email/render resend

# If you're in a Next.js project (React is usually already installed)
npm install @react-email/components @react-email/render resend

If you’re using TypeScript, the types come bundled with these packages, so no extra installs are required.


Step 2: Set up your Resend API key

Add your API key to environment variables:

In a Node.js project (.env):

RESEND_API_KEY=your_resend_api_key_here

Load it in your Node code via process.env.RESEND_API_KEY.

In a Next.js project:

  • Add to .env.local:
RESEND_API_KEY=your_resend_api_key_here
  • Restart the dev server after changing env vars.

Important: For security, do not expose your Resend API key to the browser. Use it only in server-side code (API routes, route handlers, server actions, or backend scripts).


Step 3: Create a React Email template

Create a dedicated folder for your email templates. Common patterns:

  • emails/ at project root, or
  • src/emails/ in TypeScript setups.

Example: emails/WelcomeEmail.tsx

// emails/WelcomeEmail.tsx
import * as React from 'react';
import {
  Html,
  Head,
  Body,
  Container,
  Text,
  Heading,
  Section,
  Button,
} from '@react-email/components';

type WelcomeEmailProps = {
  userName: string;
  appUrl: string;
};

export const WelcomeEmail: React.FC<WelcomeEmailProps> = ({
  userName,
  appUrl,
}) => {
  return (
    <Html>
      <Head />
      <Body style={main}>
        <Container style={container}>
          <Section style={section}>
            <Heading style={heading}>Welcome, {userName} 👋</Heading>
            <Text style={text}>
              Thanks for signing up! We’re excited to have you on board.
            </Text>
            <Text style={text}>
              Click the button below to start using your account.
            </Text>
            <Button href={appUrl} style={button}>
              Go to Dashboard
            </Button>
            <Text style={footer}>
              If you did not sign up, you can safely ignore this email.
            </Text>
          </Section>
        </Container>
      </Body>
    </Html>
  );
};

// Basic inline styles for email clients
const main: React.CSSProperties = {
  backgroundColor: '#f5f5f5',
  padding: '20px 0',
};

const container: React.CSSProperties = {
  maxWidth: '600px',
  margin: '0 auto',
  backgroundColor: '#ffffff',
  borderRadius: '8px',
  padding: '24px',
};

const section: React.CSSProperties = {
  textAlign: 'left',
};

const heading: React.CSSProperties = {
  fontSize: '24px',
  marginBottom: '16px',
};

const text: React.CSSProperties = {
  fontSize: '14px',
  lineHeight: '1.6',
  marginBottom: '12px',
};

const button: React.CSSProperties = {
  display: 'inline-block',
  backgroundColor: '#2563eb',
  color: '#ffffff',
  padding: '10px 18px',
  borderRadius: '4px',
  textDecoration: 'none',
  fontSize: '14px',
};

const footer: React.CSSProperties = {
  fontSize: '12px',
  color: '#666666',
  marginTop: '20px',
};

This component describes your email layout using familiar React patterns. Next, you’ll render it to HTML and send it.


Step 4: Render the React Email template to HTML

You can either:

  1. Let Resend handle React components directly (with react field), or
  2. Manually render to HTML with @react-email/render.

Option A: Pass the React component directly to Resend (recommended)

Resend SDK supports passing a JSX component that will be rendered server-side:

// lib/resendClient.ts
import { Resend } from 'resend';

export const resend = new Resend(process.env.RESEND_API_KEY);

Then, when sending:

import { resend } from './lib/resendClient';
import { WelcomeEmail } from '../emails/WelcomeEmail';

async function sendWelcomeEmail(to: string, userName: string, appUrl: string) {
  const { data, error } = await resend.emails.send({
    from: 'Acme <noreply@your-domain.com>',
    to,
    subject: 'Welcome to Acme!',
    react: <WelcomeEmail userName={userName} appUrl={appUrl} />,
  });

  if (error) throw error;
  return data;
}

Option B: Render manually to HTML

If you prefer to control rendering or store HTML:

import { Resend } from 'resend';
import { render } from '@react-email/render';
import { WelcomeEmail } from '../emails/WelcomeEmail';

const resend = new Resend(process.env.RESEND_API_KEY);

async function sendWelcomeEmail(to: string, userName: string, appUrl: string) {
  const html = render(
    <WelcomeEmail userName={userName} appUrl={appUrl} />,
  );

  const { data, error } = await resend.emails.send({
    from: 'Acme <noreply@your-domain.com>',
    to,
    subject: 'Welcome to Acme!',
    html,
  });

  if (error) throw error;
  return data;
}

Both approaches work well in Node and Next.js. Option A is simpler; Option B gives more control.


Step 5: Using React Email templates with Resend in a Node.js project

In a pure Node project, you typically:

  • Create an email service file
  • Import templates and the Resend client
  • Call that service from controllers or background jobs

Example: src/email/sendWelcomeEmail.ts

// src/email/sendWelcomeEmail.ts
import { Resend } from 'resend';
import { WelcomeEmail } from '../../emails/WelcomeEmail';

const resend = new Resend(process.env.RESEND_API_KEY);

type SendWelcomeEmailArgs = {
  to: string;
  userName: string;
  appUrl: string;
};

export async function sendWelcomeEmail({
  to,
  userName,
  appUrl,
}: SendWelcomeEmailArgs) {
  const { data, error } = await resend.emails.send({
    from: 'Acme <noreply@your-domain.com>',
    to,
    subject: 'Welcome to Acme!',
    react: <WelcomeEmail userName={userName} appUrl={appUrl} />,
  });

  if (error) {
    console.error('Failed to send welcome email:', error);
    throw error;
  }

  return data;
}

You can then call sendWelcomeEmail from your signup handler, cron job, or queue processor.


Step 6: Using React Email templates with Resend in a Next.js project

The process is similar, but you integrate with Next.js API routes or route handlers.

6.1 Using Next.js App Router (app/ directory) with Route Handlers

If you’re using Next.js 13+ with the App Router, create a route handler:

Example: app/api/send-welcome/route.ts

// app/api/send-welcome/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Resend } from 'resend';
import { WelcomeEmail } from '@/emails/WelcomeEmail'; // adjust path

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: NextRequest) {
  try {
    const { email, userName, appUrl } = await req.json();

    if (!email || !userName || !appUrl) {
      return NextResponse.json(
        { error: 'Missing required fields' },
        { status: 400 },
      );
    }

    const { data, error } = await resend.emails.send({
      from: 'Acme <noreply@your-domain.com>',
      to: email,
      subject: 'Welcome to Acme!',
      react: <WelcomeEmail userName={userName} appUrl={appUrl} />,
    });

    if (error) {
      console.error(error);
      return NextResponse.json({ error: error.message }, { status: 500 });
    }

    return NextResponse.json({ success: true, data });
  } catch (err: any) {
    console.error(err);
    return NextResponse.json(
      { error: err.message ?? 'Unknown error' },
      { status: 500 },
    );
  }
}

From the client, you can call:

await fetch('/api/send-welcome', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: 'user@example.com',
    userName: 'Jane',
    appUrl: 'https://app.example.com',
  }),
});

6.2 Using Next.js Pages Router (pages/api) with API Routes

If your project uses pages/, create:

pages/api/send-welcome.ts

import type { NextApiRequest, NextApiResponse } from 'next';
import { Resend } from 'resend';
import { WelcomeEmail } from '../../emails/WelcomeEmail';

const resend = new Resend(process.env.RESEND_API_KEY);

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { email, userName, appUrl } = req.body;

  if (!email || !userName || !appUrl) {
    return res.status(400).json({ error: 'Missing required fields' });
  }

  try {
    const { data, error } = await resend.emails.send({
      from: 'Acme <noreply@your-domain.com>',
      to: email,
      subject: 'Welcome to Acme!',
      react: <WelcomeEmail userName={userName} appUrl={appUrl} />,
    });

    if (error) {
      console.error(error);
      return res.status(500).json({ error: error.message });
    }

    return res.status(200).json({ success: true, data });
  } catch (err: any) {
    console.error(err);
    return res.status(500).json({ error: err.message ?? 'Unknown error' });
  }
}

This structure is ideal when you want to call the endpoint from your frontend or external services.


Step 7: Previewing React Email templates during development

One of the big advantages of React Email is its preview server.

7.1 Install the React Email CLI (optional but recommended)

npm install --save-dev react-email

Add a script to package.json:

{
  "scripts": {
    "email:dev": "react-email dev --dir=emails"
  }
}

Then run:

npm run email:dev

This opens a local UI (usually at http://localhost:3000) to preview your templates and adjust styles before wiring them to Resend.


Step 8: TypeScript tips and typing props

To keep your emails type-safe in a Node/Next.js project:

  • Export the props type from the email file
  • Reuse that type where you call the template
// emails/WelcomeEmail.tsx
export type WelcomeEmailProps = {
  userName: string;
  appUrl: string;
};

export const WelcomeEmail: React.FC<WelcomeEmailProps> = (props) => {
  // ...
};
// src/email/sendWelcomeEmail.ts
import { WelcomeEmail, WelcomeEmailProps } from '../../emails/WelcomeEmail';

type SendWelcomeEmailArgs = WelcomeEmailProps & {
  to: string;
};

export async function sendWelcomeEmail({
  to,
  userName,
  appUrl,
}: SendWelcomeEmailArgs) {
  // ...
}

This ensures that when you use your React Email templates with Resend in a Node/Next.js project, prop changes will surface as compile-time errors instead of runtime bugs.


Common pitfalls and how to avoid them

When learning how to use React Email templates with Resend in a Node/Next.js project, watch out for these issues:

  1. API key available only on the server

    • Use process.env.RESEND_API_KEY exclusively in server-side context.
    • Do not prefix with NEXT_PUBLIC_ or expose it client-side.
  2. React component rendering environment

    • Ensure your React/JSX is only used in server code (Node, API routes, route handlers).
    • Don’t import resend or email templates inside client components.
  3. JSX configuration

    • If using TypeScript, ensure jsx or jsxImportSource is set correctly in tsconfig.json. Most Next.js defaults are fine.
  4. From address configuration

    • Use a verified sending domain in Resend (e.g. noreply@yourdomain.com).
    • Verify the domain in the Resend dashboard to avoid deliverability issues.
  5. Next.js edge runtimes

    • The Resend Node SDK expects a Node.js runtime, not Edge.
    • For App Router route handlers, ensure you don’t set export const runtime = 'edge' for endpoints using Resend.

Example: Full flow in a Next.js App Router project

Putting it all together, here’s a condensed workflow for how to use React Email templates with Resend in a Next.js App Router project:

  1. Create template in emails/WelcomeEmail.tsx.

  2. Add Resend key to .env.local as RESEND_API_KEY=....

  3. Set up Resend client in lib/resend.ts:

    import { Resend } from 'resend';
    
    export const resend = new Resend(process.env.RESEND_API_KEY);
    
  4. Create route handler app/api/send-welcome/route.ts that:

    • Parses JSON body
    • Validates email, userName, appUrl
    • Calls resend.emails.send with react: <WelcomeEmail ... />
    • Returns JSON response
  5. Trigger from your app in a server action, form handler, or client-side fetch call.

This pattern scales well to multiple templates (password reset, order confirmation, newsletters) while keeping your Node/Next.js backend clean and maintainable.


Summary

To effectively use React Email templates with Resend in a Node/Next.js project:

  • Install @react-email/components, @react-email/render (optional), and resend.
  • Store your Resend API key in environment variables and only access it server-side.
  • Build email templates as React components with typed props.
  • Send emails via Resend using either the react property (component) or html (pre-rendered).
  • Integrate with Node controllers, Next.js API routes, or App Router route handlers.
  • Use React Email’s dev server to preview and refine your templates.

Following these steps will give you a robust, type-safe, and developer-friendly email stack that fits naturally into modern Node and Next.js workflows.