Build a Startup Cheatsheet

Trade-offs and When to Use What

Use this Build a Startup reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

The Core Tension in Technical Decisions

Every technical decision involves at least one of these tradeoffs:

  • Speed to build vs. long-term flexibility
  • Developer experience vs. runtime performance
  • Managed services vs. control and cost
  • Simple now vs. scalable later

There is no universally right answer. The right answer depends on your stage (zero to one vs. scaling), your team (solo founder vs. 10 engineers), your users (B2B enterprise vs. consumer), and your budget.

This page maps the most common decisions to the context where each choice wins.

Managed Service vs. Self-Hosted

Managed serviceSelf-hosted
Setup timeMinutes to hoursDays to weeks
MaintenanceProvider handles itYou handle it
Cost at low scaleOften free tierInfrastructure cost even at zero users
Cost at high scaleCan be expensiveCheaper per unit
ControlLimitedFull
Vendor lock-inHighNone
ReliabilityProvider's SLAYour ops team

When managed wins: MVP, solo founder, team without dedicated infrastructure engineering, early-stage product where velocity matters most.

When self-hosted wins: At scale where managed costs exceed infrastructure costs; compliance requirements (HIPAA, SOC 2 with specific controls); need for custom configuration that managed services do not offer.

The typical crossover point: managed services become cost-prohibitive somewhere between $10K–$100K MRR, depending on your usage patterns. Self-host when you have the engineering bandwidth and a real cost problem — not before.

SQL vs. NoSQL

SQL (Postgres)NoSQL (MongoDB, DynamoDB)
Data shapeStructured, relationalFlexible, document
SchemaEnforced, migrations requiredFlexible, schema-on-read
JoinsNative, efficientManual, limited
TransactionsFull ACIDPartial or none
Scaling writesVertical + read replicasHorizontal sharding
QueryingSQL (rich)Limited (document-level)
Best for95% of productsVariable-shape documents, extreme write scale

Choose SQL when: Your data has relationships (users → posts → comments), you need transactions (financial records), or you want to query your data flexibly.

Choose NoSQL when: Your document shapes vary wildly between records, you need horizontal write scaling across many shards at very high write volumes, or your team's expertise is in MongoDB.

Default: Postgres. The burden of proof is on NoSQL.

Server-Side Rendering vs. Client-Side Rendering

SSR (Next.js App Router default)CSR (pure React SPA)
SEOExcellent — content in initial HTMLPoor — crawlers may not execute JS
First paintFaster (HTML from server)Slower (JS must load first)
Interactivity timeSlightly slower (hydration)Fast once loaded
ComplexityHigher (server/client boundary)Lower
CachingPer-page controlCDN edge caching of JS bundle
Best forMarketing sites, content, dashboardsInternal tools, highly interactive apps

Choose SSR: Public-facing pages where SEO matters, content-heavy pages, dashboards that need fresh data on load.

Choose CSR: Internal admin tools, apps behind login where SEO is irrelevant, highly interactive UIs (rich drag-and-drop, canvas-based tools).

The realistic choice: Next.js App Router with Server Components for data-fetching routes and "use client" only where interactivity is needed. This gives you the benefits of both.

Monolith vs. Microservices

MonolithMicroservices
DeploymentOne unitMany independent services
Development speedFast (one repo, shared types)Slow (API contracts, separate deploys)
DebuggingSimple (one log stream)Complex (distributed tracing)
ScalingScale everything or nothingScale individual services
Team coordinationEasyRequires API versioning and contracts
Best for0–100 engineers100+ engineers, very high scale

Default: monolith. Extract a service only when you have a specific, measured reason: dramatically different scaling needs (a video transcoder vs. a user API), a separate team that needs independent deploy, or a language boundary (Python ML inference alongside a Node.js web server).

Netflix, Amazon, and Uber all started as monoliths and split over years. Your startup is not Netflix.

Third-Party Auth vs. Hand-Rolled Auth

Clerk / Supabase Auth / Auth.jsCustom auth
Time to implement30 min – 2 hoursDays to weeks
SecurityBattle-testedRisk of implementation errors
FeaturesOAuth, MFA, passwordless includedBuild each feature yourself
CostFree tier; $20–$25/monthInfrastructure only
Vendor lock-inMedium to highNone
ControlLimited (Clerk) to full (hand-rolled)Full
Best for99% of productsAuth IS your product

Default: use a service. The only strong argument for hand-rolling auth is if your auth model is genuinely novel (which is very rare) or if you have strict data residency requirements that services cannot meet.

Stripe vs. Custom Payments

Do not build custom payment processing. Ever. The regulatory, security, and operational overhead (PCI DSS compliance, fraud handling, chargeback management) is not worth it. Stripe's fees (2.9% + 30¢) are the cost of delegating all of that to experts.

The only edge case: very high volume where Stripe's fees become prohibitive. At that point, you negotiate a custom rate with Stripe (available at ~$1M/month processing volume) before considering alternatives.

When to Use AI vs. Deterministic Logic

Deterministic codeAI (LLM)
ConsistencyAlways same output for same inputVariable output
CostNegligible compute~$0.001–$0.05 per call
LatencyMilliseconds0.5–10 seconds
ExplainabilityFully auditableBlack box
Input flexibilityStructured, specificFreeform, natural language
Best forCalculations, validation, rulesClassification, summarization, generation

Use AI when: The task involves understanding natural language, generating text, classifying open-ended input, or extracting structure from unstructured data.

Use deterministic logic when: The rules are clear and enumerable, consistency is required (financial calculations), you need sub-100ms response time, or cost per request must be near zero.

Common mistake: Using an LLM to do things that a regex or database query would do better and cheaper.

Serverless vs. Always-On Servers

Serverless (Vercel, Cloudflare)Always-on (Railway, EC2)
Cold starts50ms–1s on first requestNone
ScalingAutomatic, to zeroManual or auto-scaling
Cost at zero load$0~$5–$20/month
Cost at high loadPer-invocation (can be expensive)Flat or predictable
Long-running jobsNot supported (15s–5min limit)Supported
WebSocketsNot supported on most serverlessSupported
Stateful processesNot possiblePossible

Use serverless when: Standard CRUD web API, no background jobs, no WebSockets, traffic is bursty.

Use always-on when: WebSockets, background workers, cron jobs, long-running processes, ML inference, or cost-effective at high sustained traffic.

GraphQL vs. REST

RESTGraphQL
SimplicitySimple, well-understoodMore complex (schema, resolvers)
Data fetchingMultiple round trips for related dataSingle query for any data shape
OverfetchingCommon (return the whole resource)Eliminated
Client flexibilityFixed endpointsClients request exactly what they need
CachingHTTP cache (GET requests)Harder (POST by default)
ToolingUbiquitousGraphQL-specific clients needed
Best forMost productsComplex data graphs, multiple clients

Default: REST. GraphQL adds significant complexity (schema, resolvers, n+1 query problems, authorization at field level). Its benefits matter when: you have multiple frontends (web + mobile + third-party) with different data needs, or your data is a complex graph that does not map cleanly to REST resources.

Choosing a Database ORM

Raw SQLQuery builder (Knex)ORM (Prisma, Drizzle)
Type safetyNonePartialFull (Drizzle, Prisma)
ControlFullHighMedium
Migration managementManualManualAutomatic
Learning curveSQL knowledge requiredLowLow
PerformanceBestVery goodGood
Best forComplex queries, DBA teamsSimple projectsMost TypeScript projects

Recommendation: Drizzle ORM for TypeScript. It generates minimal abstraction overhead, gives you SQL-like syntax, and is fully type-safe.

Framework-Level Decisions: When to Break from the Default

The default stack (Next.js + Supabase + Vercel) covers most startup use cases. Deviate when:

SituationAlternative to consider
Mobile is your primary interfaceExpo (React Native)
AI/ML is the core productFastAPI (Python) for inference
Real-time collaboration is the productConvex or Liveblocks
Heavy data pipeline or analyticsPython + Airflow/dbt
High-traffic public APIGo or Rust for latency-critical endpoints
Self-hosted auth requirementAuth.js or hand-rolled
EU data residencyHetzner Cloud (Germany), Scaleway (France), or Supabase EU region

Never choose a non-default option because it is interesting or because you read a blog post about it. Measure the problem first.