How I Build Scalable Web Apps


"Scalable" gets thrown around in job posts and README files. When I say it, I mean: the architecture can grow without a rewrite — more traffic, more features, more team members — without everything touching everything else.
I am not building Netflix on day one. I am building clear boundaries so day one does not paint me into a corner.
This is the stack and shape I use most: .NET API, React frontend, PostgreSQL, Redis. Containers when it is time to deploy — see Docker on DigitalOcean.
| Piece | Job |
|---|---|
| .NET API | Business logic, auth, validation, data access |
| React | UI, client state, forms |
| PostgreSQL | Source of truth — relational data, transactions |
| Redis | Cache, sessions, rate limits, hot reads |
What scalable does not mean on day one:
What it does mean:
I keep controllers dumb. They parse HTTP, call a service, return a result.
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
var user = await _userService.GetUserByIdAsync(id);
if (user == null) return NotFound();
return Ok(user);
}
}
Why: Unit tests hit UserService without spinning up HTTP. When load grows, I optimize the service and data layer — not routing attributes.
What: Cache expensive reads, store session keys, throttle abusive clients.
Why: Postgres is correct; Redis is fast. Not every read needs to hit disk.
Pattern I use:
Red flag: Caching before you measure. I add Redis when p95 latency or DB CPU tells me to, not because the diagram looked empty.
React talks to REST (or GraphQL) — never directly to Postgres. DTOs on the API define what the UI gets.
Why: You can change schema without redeploying the SPA. Mobile clients can share the same API later.
I have not needed step 4 on every project. I still design so a queue could pick up work without rewriting business logic.
Pick boundaries: API owns data and rules, React owns UX, Postgres owns truth, Redis owns speed and ephemeral state. Deploy with Docker when you are ready.
If you are on .NET, spend an afternoon on dependency injection — it is the glue that keeps this layout testable as the codebase grows.
Scalable is a direction, not a day-one checkbox. Build something small with clear seams. Measure. Then scale what hurts.