Choose around the product's constraints
Write down what the product needs before comparing framework names. A web dashboard, an offline mobile tool, and a long-running research workflow have different constraints. Decide which clients you need, what data belongs to each customer, and which operations must continue after a browser tab closes.
Consider your team's experience alongside feature lists. A familiar stack with clear boundaries can be easier to maintain than a newer combination that requires learning authentication, deployment, and persistence conventions at the same time. Count the ongoing work of upgrades and debugging, not just the first installation.
- Which client surfaces you need on day one — web only, or mobile and desktop too.
- What data belongs to each customer, and whether teams share workspaces.
- Which operations must outlive a browser tab: queued jobs, scheduled work, long-running tasks.
- What you will bill for — subscriptions, seats, usage — and who pays for it.
- How much operational surface your team can realistically run: databases, queues, providers.
Evaluate the layers underneath the framework
Framework names describe the surface. The layers underneath decide whether the product holds together. Walk them one at a time and ask the same question of each: who owns this decision, and where is it enforced?
Treat any layer a stack leaves blank as work you are signing up for. “Bring your own auth” is a legitimate design — it just means you will own session semantics, provider integrations, and every failure case that follows. Blank layers are a choice; invisible layers are a liability. The kit's module documentation is a useful reference for what an owned layer actually looks like.
| Layer | The question to answer |
|---|---|
| Identity | Who issues and verifies sessions, on every surface? |
| Data | How is each record scoped to its owning customer? |
| Billing | Where does a payment event become access, and who revokes it? |
| Background work | What happens when a job fails, retries, or runs twice? |
| AI and providers | Who owns the keys, the model choice, and the spend limit? |
| Operations | How do secrets, logs, backups, and upgrades actually run? |
Inspect the seams between tools
A stack is a collection of integration decisions. Find out who owns sessions, how records are scoped, where a payment event becomes an entitlement, and how the UI retrieves the result of background work. These connections determine whether the happy path remains correct when requests fail or arrive twice.
supastack uses Next.js for the web surface, Expo for mobile, and shared TypeScript packages underneath. Better Auth owns identity, Postgres and Drizzle persist records, and Trigger.dev owns explicit workflow behavior. Those are repository choices, not a claim that every product should use the same tools — the tech stack guide records each choice and its reason, and the questions transfer even if you pick different tools.
Whatever the tools, the test is the same: pick a record and trace it from the interface, through the server boundary, into persistence, and back. If any hop is a convention rather than an enforced rule, a future contributor will eventually break it.
Count the cost of keeping it running
A stack decision is also an operations decision. Postgres needs backups and migration discipline. A job runner needs a dashboard someone actually opens. Every provider key needs rotation and a home outside client bundles. Add these line items to the comparison before the feature checklist wins you over.
Check the upgrade path while you still have options. A monorepo with pinned dependencies and a documented update process — the kit maintains an update guide for exactly this — ages better than a stack assembled from tutorials that each assume a different version of the world.
- Dependency and security updates: how often they land, and who applies them.
- Provider credentials: where they live, and who can rotate them.
- Data: a backup schedule, a restore drill, and a retention policy.
- Observability: what breaks loudly, and what fails silently until a customer reports it.
Build a small vertical slice
Before committing to a stack, run a slice that signs a user in, writes an owned record, starts work, and retrieves a result. Then deliberately try the wrong workspace, an expired session, and a failed job. Evaluate how much custom glue those ordinary conditions require.
Keep a short decision record: what the stack supports, what you are choosing to postpone, and what would trigger a revisit. Native purchasing, real-provider acceptance, and deployment operations should be explicit items rather than assumptions hidden behind a successful local build. The right stack leaves the team enough attention to work on the product.
If the slice goes well inside a starter's repository, the follow-up question is whether to adopt it — starter kit or from scratch walks through that decision.
- Sign in, then restore the session after a reload.
- Write a record scoped to one workspace and read it back.
- Start a background task and retrieve its result later.
- Repeat the same calls from the wrong workspace and an expired session.
Common questions about choosing a stack
Stack decisions attract a lot of confident advice. These are the questions worth answering for your own product instead.
- Should I pick the stack I already know? — Usually yes, when it can express the product's constraints. A familiar stack with clear boundaries beats a fashionable one you will spend months learning — unless the product genuinely requires something it lacks, like native mobile.
- Does the front-end framework matter most? — Less than the layers around it. The framework shapes the UI; identity, scoping, billing, and background work decide whether the product stays correct.
- How long should a stack evaluation take? — Days, not weeks: write the constraints, inspect the seams, and run one vertical slice. If ordinary failures need custom glue, keep looking.
- When is switching stacks later justified? — When a core constraint changes — a required platform, a scale threshold — not when a newer release looks nicer. The switching cost lives in auth and data, not in components.