Skip to main content

Best Boilerplates for Newsletter & Email Products 2026

·StarterPick Team
newsletteremailsubscribersboilerplate2026

Newsletter Platforms: Platform vs Custom

Newsletter businesses have exploded in 2024-2026. Substack's success spawned alternatives (Beehiiv, Kit formerly ConvertKit, Lemon Squeezy, Buttondown), each with different takes on monetization and design.

Build a custom newsletter platform when: you're building a platform for newsletter operators (like Beehiiv), your newsletter needs deep integration with other product features, or you need white-label email publishing.

Platform Decision

PlatformCostTake RateBest For
SubstackFree10%Discovery-focused newsletters
Beehiiv$42-$99/mo0%Scale-focused newsletters
Ghost$9-$199/mo (self-host free)0%Tech-savvy creators
Kit (ConvertKit)$9+/mo0%Marketing-heavy creators
CustomDev time0%Platform builders

For most newsletter creators: Ghost (self-hosted) or Beehiiv. Build custom only when you're building the platform itself.

Ghost — Best Open Source Newsletter Platform

Price: Free (self-host) / $9-$199/month (Ghost Pro) | Creator: Ghost Foundation

Ghost 5.x has excellent newsletter functionality: subscriber segments, scheduled sends, email analytics (open rate, click rate), paid memberships (Stripe), and portal widget for embeds.

# Self-host Ghost on Railway (cheapest managed option)
# Cost: ~$5/month (Railway Hobby plan)

ghost install --db sqlite3  # SQLite for small newsletters
# or
ghost install --db mysql    # MySQL for larger newsletters

Email delivery: Ghost uses Mailgun by default. Budget: ~$15/month for 50k sends.

Building a Custom Newsletter Platform

For building a newsletter product (not just running a newsletter):

// Core newsletter data model
model Newsletter {
  id           String        @id @default(cuid())
  slug         String        @unique
  name         String
  description  String?
  owner        User          @relation(fields: [ownerId], references: [id])
  ownerId      String
  subscribers  Subscriber[]
  posts        Post[]
  // Stripe for paid subscriptions
  stripeProductId String?
  stripePriceId   String?
}

model Subscriber {
  id           String     @id @default(cuid())
  email        String
  newsletter   Newsletter @relation(fields: [newsletterId], references: [id])
  newsletterId String
  status       SubscriberStatus @default(ACTIVE)  // ACTIVE, UNSUBSCRIBED, BOUNCED
  tier         String     @default("free")  // free, paid
  stripeSubId  String?    // If paid subscriber
  openCount    Int        @default(0)
  clickCount   Int        @default(0)
  joinedAt     DateTime   @default(now())
  @@unique([email, newsletterId])
}

Email Sending Infrastructure

For a newsletter platform, you need a transactional email provider that supports:

  • High volume (millions of sends per month)
  • Domain verification (DKIM, SPF, DMARC)
  • Bounce handling (auto-unsubscribe hard bounces)
  • Unsubscribe processing (honor unsubscribes automatically)

Best providers for newsletter platforms:

  1. Resend — Best developer experience, $20/month for 100k emails
  2. AWS SES — Cheapest at scale, $0.10 per 1000 emails
  3. Postmark — Best deliverability reputation, $15/month for 10k emails
  4. Mailgun — Good balance, $35/month for 100k emails
// Send newsletter issue via Resend
import { Resend } from 'resend';

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

// Batch send (respect rate limits)
async function sendIssue(issueId: string) {
  const issue = await db.post.findUnique({
    where: { id: issueId },
    include: { newsletter: { include: { subscribers: { where: { status: 'ACTIVE' } } } } },
  });

  // Send in batches of 100
  const batches = chunk(issue.newsletter.subscribers, 100);
  for (const batch of batches) {
    await resend.batch.send(
      batch.map(subscriber => ({
        from: `${issue.newsletter.name} <newsletter@yourdomain.com>`,
        to: subscriber.email,
        subject: issue.title,
        html: renderEmailTemplate(issue, subscriber),
        headers: {
          'List-Unsubscribe': `<https://yoursite.com/unsubscribe/${subscriber.id}>`,
          'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',
        },
      }))
    );
    await sleep(1000);  // Respect rate limits
  }
}

Compare newsletter and SaaS boilerplates on StarterPick.

Check out this boilerplate

View Ghost on StarterPick →

Comments