Short answer
Scale vertically first when the bottleneck is a single component that resists partitioning (a relational primary, an in-memory cache) and you're below the hardware ceiling; it needs no code changes.
Explanation
Horizontal scaling is harder because it demands a stateless tier (no in-memory sessions, locks, or local file state), a load balancer, and shared backing stores, and it surfaces distributed concerns like cache coherence and replication lag. In practice the limit of vertical scaling is the database, so you eventually combine both: scale the app tier out, and scale the data tier with replicas and sharding.
Common mistakes
- Saying horizontal scaling is always better.
- Ignoring state (sessions, caches) that blocks horizontal scaling.