Writing, a subscriber list and a send button make a weekend project, and a Stripe-backed paid tier fits in the same weekend: Ghost already does exactly that if you'd rather not build. What a copy cannot bring is what the 10% buys beyond payments: the app and inbox where readers already are, Notes and recommendations that send new subscribers, and a sending reputation that gets mail delivered. Leaving only saves money if your readers find you without Substack's help.
Before you buildSubstack costs nothing until you charge readers. If your newsletter is free, there is nothing to save by leaving.
Build me a self-hosted newsletter with a paid tier to replace Substack. Requirements: - Node.js 22 + TypeScript: a Fastify server with server-rendered pages (Eta) and no front-end framework. `npm start` serves http://localhost:4400; admin at /admin. - Storage: better-sqlite3 in ./data/letter.db: subscribers (email, status pending / active / unsubscribed, tier free / paid, stripe_customer_id), posts (slug, title, markdown, audience everyone / paid, status draft / sent) and deliveries (post, subscriber, state, sent_at). - Writing: a Markdown editor with live preview (`marked`), drafts and "send test to me". A line `<!-- paywall -->` splits a post: free readers get the text above it and a subscribe button. - Sending: nodemailer SMTP from .env (Amazon SES or Resend). Batches at SEND_RATE per second; each recipient's state is written before the send, so a restart never mails anyone twice. Paid posts go to paid subscribers only; everyone else receives the free part. - Signup: double opt-in with a 48-hour token. Every email carries an unsubscribe link plus List-Unsubscribe and List-Unsubscribe-Post headers. - Paid tier: Stripe Checkout in subscription mode (monthly and yearly prices created in the Stripe dashboard, ids in .env) and the Stripe Customer Portal for changing or cancelling. /stripe/webhook verifies the signature and handles checkout.session.completed, customer.subscription.updated and customer.subscription.deleted. No card data touches the server. - Reading: /archive and /p/<slug> for public posts. Paid posts open from a signed magic link emailed to an active paid subscriber (cookie for 30 days). /feed.xml lists public posts only. - Admin: one password in .env (signed cookie); subscriber CSV import and export. - Single user. No telemetry. Outbound calls: SMTP and Stripe only. - Out of scope: Notes, recommendations, comments, podcasts, in-app purchases, tax handling. - README: the SPF, DKIM and DMARC records, `stripe listen --forward-to` for local tests, the webhook events to enable, and a warning that a new SES account starts in the sandbox.
Opens your agent with the prompt filled in, you press enter. Or copy it and paste it into an empty folder.
The first prompt builds the core. Run these one at a time in the same folder to grow it into your own Substack.
Add a Substack importer to the newsletter app in this folder. Requirements: - Accept the zip from Substack's Exports page. Inspect the actual layout first, list what it contains, and stop with a clear message if you don't recognise it. - Convert each post's HTML to Markdown (`turndown`), keep the slug, title and date, and mark posts as paid or public as the export says. - Read the free and paid subscriber CSVs; create subscribers as active and keep the signup date. Match paid ones to Stripe customers by email using the Stripe API (STRIPE_SECRET_KEY in .env). - Never send anything during an import; print a summary of imported and skipped rows. - Update the README, including the warning that readers should be told before the first send.
Add bounce handling to the newsletter app in this folder. Requirements: - An endpoint that receives Amazon SES notifications through SNS (confirm the subscription and verify the message signature). - A hard bounce or a spam complaint marks the subscriber as suppressed, and suppressed addresses never receive another issue. - Soft bounces count; after 3 in a row, suppress. - The admin shows suppressed addresses with the reason and a way to clear one. - Update the README with the SES and SNS setup steps.
Add a welcome sequence to the newsletter app in this folder. Requirements: - Three emails written in Markdown in the admin: sent right after confirming, 2 days later and 5 days later. - A worker checks every minute, sends what is due and records each step per subscriber so nobody gets one twice. - Stop the sequence when someone unsubscribes or becomes a paid subscriber. - Update the README.
Extend the paid tier of the newsletter app in this folder. Requirements: - A "comped" flag on a subscriber, set from the admin, that grants paid access with an optional end date and no Stripe record. - A third Stripe price for a founding tier, shown on the subscribe page next to the others; founding members read the same paid posts. - The admin lists paid, comped and founding counts and monthly recurring revenue from Stripe. - Update the README.
It costs nothing until a reader pays, so starting carries no risk, and the signup page, payments, archive and apps arrive in one account. Substack's own pitch is that writers keep 90% of their revenue minus card fees, with no bill when the newsletter earns nothing.
Checked 2026-10-14 against Substack's docs: 1, 2, 3, 4, 5, 6
| Plan | Monthly | Annual, per month | What you get |
|---|---|---|---|
| Free publication | $0 | $0 | No cap on subscribers or posts. |
| Paid subscriptions | custom | — | Substack keeps 10% of each subscription payment. Stripe adds 2.9% + $0.30 per US card payment and 0.7% for recurring billing. |
Publishing is free at any subscriber count; fees begin only when you charge readers.
Kinda. The core is a weekend build with the prompt on this page, but real gaps remain: Notes, recommendations and the Substack app, which send readers to you, Readers who already have Substack accounts and subscribe from inside the app.
Substack's pricing is usage-based or varies by plan.
Notes, recommendations and the Substack app, which send readers to you; Readers who already have Substack accounts and subscribe from inside the app; Podcast hosting, video posts and reader chat in the same place; Apple in-app purchases for readers who subscribe on iOS; A sending reputation built over years: a new domain starts cold. If any of those matter to you, keep paying.
Yes: Ghost (open source), listmonk (open source), Keila (open source).