Site name
Technical Tutorials

Secure MailerLite Integration with Next.js 15: A Step-by-Step Guide

PMTheTechGuy
··3 min read
Secure MailerLite Integration with Next.js 15: A Step-by-Step Guide cover image

Pasting a third-party script into your website is easy. But for a professional portfolio, it's often the wrong choice. It can slow down your site, leak customer data to trackers, and expose your private API keys.

In this guide, I'll show you how to build a server-side bridge between your Next.js 15 frontend and the MailerLite API.

Why Build Your Own API Route?

If you call MailerLite (or any service) directly from the browser, your API Key is visible to anyone who opens the "Network" tab in their developer tools. A malicious user could then use your key to delete your subscribers or spam your list.

By building an internal API route, your secret key stays on the server. Your website talks to your server, and your server talks to MailerLite.

Step 1: Secure Your Environment Variables

First, we need to ensure our keys are never sent to the browser. In Next.js, keys prefixed with NEXT_PUBLIC_ are accessible on the client. We want to avoid that.

Create a src/lib/env.server.ts file to validate and export your secrets:

import "server-only"; // Ensures this file never runs on the client
 
type ServerEnv = {
  MAILERLITE_API_KEY: string;
  MAILERLITE_GROUP_ID: string;
};
 
const mailerliteApiKey = process.env.MAILERLITE_API_KEY?.trim();
const mailerliteGroupId = process.env.MAILERLITE_GROUP_ID?.trim();
 
if (!mailerliteApiKey || !mailerliteGroupId) {
  throw new Error("Missing MailerLite credentials in .env.local");
}
 
export const serverEnv: ServerEnv = Object.freeze({
  MAILERLITE_API_KEY: mailerliteApiKey,
  MAILERLITE_GROUP_ID: mailerliteGroupId,
});

Step 2: Create the API Route

In Next.js 15, we use the App Router's Route Handlers. Create this at src/app/api/newsletter/route.ts:

import { NextResponse } from "next/server";
import { serverEnv } from "@/lib/env.server";
 
export async function POST(req: Request) {
  try {
    const { email, source, resource_requested } = await req.json();
 
    if (!email) {
      return NextResponse.json({ error: "Email is required" }, { status: 400 });
    }
 
    const response = await fetch("https://connect.mailerlite.com/api/subscribers", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": `Bearer ${serverEnv.MAILERLITE_API_KEY}`,
      },
      body: JSON.stringify({
        email,
        groups: [serverEnv.MAILERLITE_GROUP_ID],
        fields: {
          source: source || "website",
          resource_requested: resource_requested || "none",
        },
      }),
    });
 
    const data = await response.json();
 
    if (!response.ok) {
      return NextResponse.json({ error: data.message || "Failed to subscribe" }, { status: response.status });
    }
 
    return NextResponse.json({ success: true });
  } catch (error) {
    return NextResponse.json({ error: "Internal server error" }, { status: 500 });
  }
}

Step 3: Connect Your Frontend

Finally, update your React component to call your new internal endpoint:

const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setStatus("submitting");
 
    try {
        const res = await fetch("/api/newsletter", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ 
                email, 
                source: "blog_footer", 
                resourceId: "technical_tutorial" 
            }),
        });
 
        if (res.ok) {
            setStatus("success");
            setEmail("");
        } else {
            const data = await res.json();
            throw new Error(data.error);
        }
    } catch (err) {
        setStatus("error");
        setErrorMessage(err.message);
    }
};

Conclusion

This setup gives you:

  1. Security: API keys are locked on the server.
  2. Tracking: You know exactly where your leads are coming from.
  3. Speed: No heavy third-party tracking scripts slowing down your initial page load.

If you found this useful, subscribe to my newsletter (yes, it really works now!) for more technical deep-dives into automation and web performance.

Tags

#Next.js#MailerLite#API#Web Development#TypeScript
Newsletter

Stay updated with my latest projects

Get notified when I publish new tutorials, tools, and automation workflows. No spam, unsubscribe anytime.

Follow Me

Share This Post

You might also like