
How do I use React Email templates with Resend in a Node/Next.js project?
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:
reactandreact-dom(already included in most Next.js apps)@react-email/componentsand optionally@react-email/renderresend(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, orsrc/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:
- Let Resend handle React components directly (with
reactfield), or - 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:
-
API key available only on the server
- Use
process.env.RESEND_API_KEYexclusively in server-side context. - Do not prefix with
NEXT_PUBLIC_or expose it client-side.
- Use
-
React component rendering environment
- Ensure your React/JSX is only used in server code (Node, API routes, route handlers).
- Don’t import
resendor email templates inside client components.
-
JSX configuration
- If using TypeScript, ensure
jsxorjsxImportSourceis set correctly intsconfig.json. Most Next.js defaults are fine.
- If using TypeScript, ensure
-
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.
- Use a verified sending domain in Resend (e.g.
-
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:
-
Create template in
emails/WelcomeEmail.tsx. -
Add Resend key to
.env.localasRESEND_API_KEY=.... -
Set up Resend client in
lib/resend.ts:import { Resend } from 'resend'; export const resend = new Resend(process.env.RESEND_API_KEY); -
Create route handler
app/api/send-welcome/route.tsthat:- Parses JSON body
- Validates
email,userName,appUrl - Calls
resend.emails.sendwithreact: <WelcomeEmail ... /> - Returns JSON response
-
Trigger from your app in a server action, form handler, or client-side
fetchcall.
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), andresend. - 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
reactproperty (component) orhtml(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.