Every pre-revenue stack decision gets re-litigated for weeks and then never revisited after launch. That is backwards. Pick the default, ship, and only deviate when a named constraint forces it. Here is the stack we actually run, and the specific condition under which each choice is wrong.

The Defaults

Layer Default Deviate when
Hosting Cloudflare Workers You need long-running processes, raw TCP, or more than 128 MB of memory per request
Database D1 You need multi-region writes, joins over 10 GB, or Postgres-only features like advisory locks
Auth JWT plus magic links You are selling to enterprises that require SAML or SCIM on day one
Payments Stripe You sell in a market Stripe does not support, or you need merchant-of-record tax handling
Email Resend You are sending more than roughly 100,000 messages a month and per-message price starts to matter

Why Workers Before a VM

The argument for edge functions at this stage is not latency. It is that there is no machine to patch, no disk to fill, and no process to restart. Those three things cause most pre-launch incidents, and Workers removes all of them by default. Deploys are atomic and roll back in one command.

The real cost is discipline. A 30-second CPU ceiling and no local filesystem means anything slow has to become a queue consumer instead of a request handler. That constraint is good for you at this stage; it forces the background-job boundary you would otherwise defer for a year.

Why D1 Before Managed Postgres

D1 is SQLite. For a product with fewer than 100 paying accounts, your entire dataset fits in memory on a phone, and every query you will write is a single-table lookup or a two-table join. Paying $25 a month and adding a connection pool to serve that is optimisation without a problem.

Be honest about the ceiling. D1 gives you one writable primary, no logical replication, and no extensions. The moment you need a second write region or a query planner you can reason about at 50 GB, you migrate. Keep migrations in plain SQL files from commit one and that migration costs a weekend, not a rewrite.

Why Magic Links Beat Passwords

A password field is a permanent obligation: hashing parameters, breach monitoring, reset flows, rate limits on three endpoints instead of one. Magic links delete all of it and move the security boundary to the mailbox, which your users already protect better than they protect a reused password.

Cap link lifetime at 15 minutes, make links single-use, and bind them to one email address rather than a session. Then issue a short-lived access token and a refresh token in an httpOnly cookie. That is the whole design, and it does not change when you add a team plan.

Where People Get Payments Wrong

The mistake is not choosing the wrong provider. It is treating the provider as the source of truth for entitlement. Stripe knows what was charged; only your database knows what the customer is allowed to do right now. Store subscription state in your own table, updated by webhooks, and read entitlement from that table on every request. Never call the Stripe API in a request path a user is waiting on.

The One-Page Checklist

  • Hosting is on a platform where a deploy is atomic and reversible in one command.
  • Every schema change exists as a numbered SQL migration file in the repository, applied by a script, never by hand.
  • You have restored a database backup into a scratch environment at least once, and the procedure fits in three sentences.
  • Auth issues a short-lived access token and stores the refresh token in an httpOnly, secure cookie.
  • Entitlement is read from your own subscription table, not from a live provider API call.
  • All secrets are in the platform’s secret store, not in a committed file or a build argument.
  • Outbound email sends through one provider with SPF, DKIM, and DMARC verified before your first campaign.
  • You can name the specific condition that would make you change each layer, and none of them have occurred yet.

The point of a default stack is not that it is optimal. It is that it removes five decisions from every week so the remaining time goes into the product. Deviate on evidence, not on preference.

Get articles like this by email

Production patterns, checklists, and failure stories for people shipping SaaS. No spam.