Adds accounts and paid memberships to a site that has no backend, by dropping in a script that gates content and talks to Stripe.
Build me accounts and paid memberships that replace Memberstack: sign-in and gated content on a site that has no backend of its own. STACK - Node 20+ with Fastify — the small backend that the static site does not have - SQLite through better-sqlite3, WAL mode - A client script under 12KB gzipped, from my own domain - One payment provider, hosted checkout, so no card data ever touches this - Caddy in front THE SHAPE OF THE PROBLEM - The site is static: HTML on a CDN, no server. That is why the product exists - So gating must happen somewhere real. Two honest options, and pick deliberately: - Gate at the edge: the reverse proxy checks the session cookie before serving the protected path. Genuinely private, and the right answer for anything that matters - Gate in the browser: the script hides content until the session is verified. Convenient, and the content is one view-source away from anyone who wants it - Say which one you have chosen, in the README, in one sentence. A product that implies the second is the first is selling a lock that is painted on THE DATA MODEL - members: id, email, email_verified_at, name, status, plan_id, external_customer_id, metadata_json, created_at, last_login_at - sessions: id, member_id, token_hash, ip_hash, user_agent_bucket, created_at, expires_at, revoked_at - plans: id, name, kind, price_cents, currency, interval, provider_price_id, features_json, is_active - subscriptions: id, member_id, plan_id, provider_subscription_id, status, current_period_end, cancel_at, cancelled_at, trial_ends_at - entitlements: derived from subscription status and plan features. Never a stored flag that can drift from the truth - magic_tokens: id, member_id, token_hash, kind, expires_at, used_at - webhook_events: id, provider_event_id, kind, payload_json, processed_at — idempotency lives here - audit: id, member_id, action, ip_hash, at AUTHENTICATION - Magic links by default. Nobody wants another password, and there is nothing here worth the risk of storing one - Password optional if a site insists, with argon2id and nothing else - Tokens are long random strings stored hashed, single-use, short-lived, invalidated on use, compared in constant time - Session cookie httpOnly, secure, sameSite lax, on the parent domain so the static site and this backend share it - Rate limits per address hash and per account on every authentication route, with the same response and the same timing for an unknown address as for a wrong password - Sign-in with a provider only if genuinely needed; it is another dependency and another privacy conversation PAYMENTS - Hosted checkout from the provider. This application never sees a card number, which keeps it out of the hardest compliance entirely - Webhooks with signature verification, idempotency by event id, and out-of-order delivery handled — the subscription-updated event routinely arrives before the checkout-completed one - The local subscription state is a mirror of the provider's. Reconcile nightly and alert on any disagreement - The provider's own customer portal for changing a card, upgrading and cancelling. Building that yourself is weeks of work for a worse result - Trials, proration and cancellation at period end all handled by the provider; this only records the outcome GATING - A verification endpoint the edge or the page calls: given the session cookie, return the member and their entitlements. Cached briefly, with an ETag - Server-side gating configured as path patterns mapped to required entitlements, enforced in the proxy - Client-side gating as attributes in the markup — show this to members, this to a plan, this to nobody signed in — with the honest caveat attached - Redirect an unauthenticated visitor to sign in and back to where they were, with the return path validated against an allow-list so it cannot be used to bounce somebody off-site THE CLIENT SCRIPT - Sign in, sign out, current member, and the gating attributes - No layout flash: gated regions start hidden and are revealed, never the other way round - Forms work without JavaScript where they can — the sign-in form is a plain POST - Nothing about a member's plan is trusted from the browser. The script displays; the server decides MEMBER MANAGEMENT - A page for the member: their plan, their billing through the provider's portal, their profile, and a way to delete their account - An admin list with search, plan, status and the audit trail - Export members as CSV, complete OPERATIONS - .env: DATABASE_PATH, BASE_URL, COOKIE_DOMAIN, SESSION_SECRET, HASH_SALT, SMTP_URL, PROVIDER_KEY, PROVIDER_WEBHOOK_SECRET - Migrations on boot, each once - Nightly backup off the machine, restore script — this holds your paying members - Health endpoint that checks the database, mail and the provider WHAT MATTERS MOST Webhook idempotency and where the gate actually is. Build the event table with the provider's event id as a unique key and replay a duplicate to prove it, then decide edge or browser gating deliberately and write down which. Everything else here is forms. Give me the repository, the client script, the edge configuration for gating, migrations, .env.example, and a README with deploy steps behind Caddy and the gating choice explained.
What you lose
- Accounts and gating on a purely static site, with no backend to run
- Stripe subscription handling, plans and the customer portal already wired
- Login, password reset and email verification already built
If you would rather not build
- Astro with a Node adapter plus Stripe
- Outseta, for the hosted version
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $29/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
Ghost
$0Memberships and Stripe already built, with server-side gating.
TryGhost/Ghostfree · open source
SuperTokens
$0Self-hosted authentication if you would rather not write the session layer.
supertokens/supertokens-corefree · open source
Why this verdict
our own opinion · changed only by a person
78/100
Verdict yes at 78, with a correction worth reading: client-side gating never protected anything. A small server does, and it is a weekend.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Memberstack
answered from the record above
Is Memberstack free?
No — the plan we track is $29 a month. Starter at around $29/month billed monthly, cheaper annually.
Can you replace Memberstack by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 78 out of 100, build time one session. Read what you lose before you decide.
How much does Memberstack cost?
$29 a month on Starter — $348 a year. Recorded 10 Aug 2026.
What do you lose by replacing Memberstack?
Accounts and gating on a purely static site, with no backend to run; Stripe subscription handling, plans and the customer portal already wired; Login, password reset and email verification already built. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Memberstack?
Yes: Ghost, SuperTokens. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

