A few years ago, if you had asked me what system design was, I probably would’ve said something like "backend stuff, right?" 😅
I was great at building UIs, designing components, and getting things pixel-perfect.
But when it came to structuring large-scale frontend applications, making trade-offs, or just knowing how to communicate design decisions, I felt... completely lost.
And the thing is - I’m not alone.
System design can feel like a black-box, especially for frontend engineers.
Most of us aren’t taught how to think about it. We’re just expected to magically know.
I messed up projects. I over-engineered where I shouldn’t have.
And sometimes, I just froze - because I didn’t know where to start.
I realised I couldn’t keep winging it.
I started asking better questions, learning from smarter folks, observing how teams made decisions - and most importantly, writing it all down.
Here are 7 things I wish I had known earlier - lessons that would’ve made me a better engineer, faster, and definitely saved me a few headaches.
1. System Design Isn’t Just for Backend Engineers
It took me way too long to realize that frontend systems need design too.
I used to think system design was mostly about backend things - like databases, queues, and server scaling. But on the frontend, we make equally important decisions every day.
You're not just placing buttons on a page. You're deciding:
- How the page loads
- When data is fetched
- What happens if something fails
- How to keep things fast and smooth for the user
Let me give you a few quick examples:
A travel homepage (like Airbnb):
You want it to load fast, feel personal, and also be SEO-friendly.
Should you render it on the client, server, or use static generation? Each has pros and cons. Picking one means thinking about performance, infra, and user experience. That’s system design.An internal dashboard: No SEO needed, but tons of data and filters.
You might use client-side rendering, debounce search input, and show skeleton UIs while loading. All small things - but together, they make or break the experience.A blog or marketing site: Rarely changing content? Great candidate for static generation + CDN.
That’s a conscious design call too.
These are everyday decisions. But when you step back and look at them, they're not just "frontend choices" - they're system choices.
And I wish I had realized that sooner.
2. Start with Questions, Not Solutions
One of the biggest mistakes I made early on was jumping straight into diagrams.
The moment someone asked me to design a system, I’d start drawing boxes, talking about React, maybe throwing in a Redux for good measure 😅
But I had no idea why I was making those choices.
Over time, I learned that the best engineers don’t start with architecture.
- They start with questions.
- They pause. They listen.
- They try to understand the problem before jumping into a solution.
Here are some of the questions I now ask - whether I’m in an interview or building something at work:
Problem & Context
- What is the core goal of this system?
- Who are the users?
- What’s the first thing they need to see?
- Are there different user roles (admin, guest, etc.)?
Scope & Constraints
- What’s in scope? What’s explicitly out of scope?
- Are there time constraints, team size limits, or tech restrictions?
- Should this work on mobile, desktop, tablets?
Performance & Experience
- Do we care about SEO? (i.e. should we consider SSR or SSG?)
- What kind of performance is expected? (First load, interactions)
- Is this expected to work offline or in low-network conditions?
Edge Cases & Reliability
- What happens when the API fails?
- What should the user see during loading? Empty state? Errors?
- Do different users see different versions of the UI?
Asking these questions has changed everything for me.
Now, instead of throwing tech at the wall and hoping it sticks, I build systems that are designed with purpose.
Because when you ask better questions, you make better decisions.
3. Performance Isn’t Just an Afterthought
There was a time when I’d build an entire app, make sure all the features were working, and only then start thinking about performance.
Unsurprisingly, it often led to painful fixes, unnecessary rewrites, and slow experiences that frustrated users and me.
I used to treat performance like a finishing touch. But eventually, I realized that performance isn’t something you sprinkle on at the end. It’s something you design for from the beginning.
One mindset shift that helped me was setting a clear, simple performance goal at the start of a project. For example, just deciding early that "the first screen should load in under 2 seconds on 4G" shaped every technical choice I made after that. It wasn’t about chasing perfection or Lighthouse scores, it was about building something usable, fast, and intentional.
Performance is not about one magical trick. It’s about small, thoughtful choices that add up. Here are some of the things I now consider early in the design process:
Over time, I built a habit of thinking about performance as part of system design. Here are some of the things I now consider early:
- I lazy-load non-critical components, so the user isn’t blocked waiting for everything at once.
- I split large JavaScript bundles, so the browser doesn’t stall parsing huge files.
- I preload above-the-fold assets to improve the time-to-first meaningful paint.
- I compress images, and prefer modern formats like WebP to reduce size without losing quality.
- I defer loading content that’s below the fold, especially on mobile.
- I use skeleton loaders instead of spinners to create a smoother perceived experience.
- I cache API responses where possible to avoid unnecessary network calls.
- I virtualize long lists or large tables, especially in dashboards and internal tools.
- I debounce or throttle expensive interactions, like live search or input-heavy forms.
- I avoid unnecessary re-renders in React using tools like React.memo or useCallback.
- I add resource hints like dns-prefetch, preconnect, and preload for critical resources.
You don’t need to implement all of these in every project. But being aware of them early lets you make smarter, more intentional design decisions.
These days, performance is no longer something I "get to later". It’s part of how I think from day one.
4. Trade-Offs Matter More Than "Right Answers"
When I started learning system design, I thought the goal was to find the best solution - the one with the cleanest code, the best architecture, and zero compromises.
But over time, I learned something more valuable:
There’s rarely one "right" answer. What matters more is understanding and explaining the trade - offs.
As frontend engineers, we make these kinds of decisions all the time:
For example, I once had to decide between using client-side rendering (CSR) or integrating server-side rendering (SSR) for a new product detail page.
- CSR would be simpler and fit right into our existing setup, but the team wanted better SEO for product discovery.
- SSR would improve crawlability, but it added complexity we hadn’t dealt with before.
We eventually decided to go with CSR for the initial release, and planned to introduce SSR for high-impact pages later. That wasn't a perfect solution - but it let us move faster while keeping future needs in mind.
Another time, I worked on a filter-heavy table for an internal dashboard.
The backend APIs were flexible, so we had two options:
- Fetch all data at once and filter it on the client, or
- Fetch filtered results on demand with every interaction.
We chose client-side filtering for simplicity and speed at small scale, knowing that we’d eventually have to switch if the data grew too large.
Neither solution was perfect. But both worked - because we made the decision consciously.
That’s the real skill in frontend system design: Not picking the "best" tech, but knowing what you’re trading off and being able to say, "Here’s what I’m choosing, and here’s why it makes sense for now."
In a nutshell, IMO Design isn’t about being right. It’s about being thoughtful.
5. Design for the Team, Not Just Yourself
There was a phase where I really loved writing "clever" code.
Reusable hooks, abstracted components, custom configurations, dynamic props - everything looked clean and powerful to me.
But I slowly started noticing something.
Other folks on the team - especially newer devs or folks who hadn’t worked on that part of the codebase - struggled to make sense of what I’d built.
What I thought was "Clean and DRY" was actually "hard to follow and scary to touch."
That’s when I realised: good system design isn’t about showing off. It’s about building something others can work with.
Now, when I’m designing a component, flow, or data structure, I ask myself:
- Will this be easy to onboard into?
- Can someone new understand this in 10-15 minutes?
- If I’m on leave, will someone else be able to debug this?
I’ve also started embracing boring, obvious solutions.
Things like:
- Writing components that are slightly repetitive but readable
- Adding in-line comments for future context
- Avoiding over-abstraction, even if the logic looks a bit duplicated
- Creating clear folders and naming things with intent, not cleverness
It’s not about dumbing things down. It’s about being kind to your team, to your future self, and to anyone else who might touch your system months later.
Because the best frontend systems?
They’re not the ones that look smartest.
They’re the ones that let everyone build confidently - without fear of breaking things.
6. State Management is a Design Problem
For the longest time, I treated state as "just another implementation detail."
If something needed to remember its value, I’d chuck it into useState, or maybe Context if it was "global."
No real plan. Just vibes.
But over time, I started noticing how often state caused bugs, confusion, and painful refactors.
And I realised: where state lives, how it flows, who owns it - that’s not just a coding problem.
That’s a system design problem.
I’ve seen components break because the state was shared across places that shouldn’t talk to each other.
I’ve seen teams struggle to manage loading flags, local UI state, backend data, and user preferences - all tangled together in one giant store.
Here’s what I’ve learned: The best systems have a clear state plan before a single line of code is written.
Now when I approach state, I ask:
- What kind of state is this? (UI state? server state? app-level config?)
- Where should it live? (local component? context? server cache like React Query?)
- Who should own it? (can it be co-located or does it need to be lifted?)
- Does it need to persist between routes or sessions?
Sometimes, the answer is simple - like using useState for a toggle.
Other times, it’s better to reach for tools like Zustand, Redux Toolkit, or React Query if the state is shared or tied to API responses.
And sometimes… I don’t need a library at all.
Just a clear, intentional structure.
The goal isn’t to "use the best tool."
The goal is to design a flow where the right data lives in the right place - and the team can reason about it without going through five layers of context.
Once I started thinking about state like part of the system architecture, not just component logic, everything became smoother: fewer bugs, easier debugging, and way less stress when the app grew.
7. The Real Skill is Communication
When I first heard the phrase "system design," I thought it was all about architecture diagrams, performance tricks, and naming patterns I hadn’t memorised yet.
But the more I grew as an engineer, the more I saw that the people who stood out weren’t always the ones with the fanciest answers - they were the ones who could communicate their thinking clearly.
In interviews, in design reviews, or even just whiteboarding with teammate, being able to say:
- "Here are the options I considered…"
- "I chose this because of X, even though it comes with Y."
- "If the scale grows, we can evolve the system like this…"
That kind of communication builds trust.
It shows that you’re not just throwing tech around - you’re thinking, planning, and designing on purpose.
I’ve had rounds where I didn’t get everything right.
I didn’t pick the exact pattern they were expecting.
But I got the role - because I asked good questions, explained my reasoning, and stayed calm under ambiguity.
And honestly? That mirrors the real world.
You’ll never have all the context.
You’ll rarely be 100% certain.
But if you can think out loud, involve others in your process, and show that you're weighing decisions thoughtfully - that’s what system design is actually about.
In the end, it’s not about being perfect.
It’s about being clear, collaborative, and adaptable.
And that’s a skill worth practicing.
What happened after I learned all this?
Once I started looking at frontend system design this way, everything shifted.
I stopped jumping into code without a plan.
I started asking better questions.
I began thinking more like a builder - with structure, clarity, and intention.
And over time, I built a system for myself - a mental checklist I could follow.
- It helped me in interviews.
- It helped me in real projects.
Not because I have all the answers.
But because I wish someone had handed me something like this when I was struggling to make sense of it all.
That’s when I decided to turn it into a handbook.
📘 Frontend System Design: The Guide I Wish I Had - a practical guide for engineers who want to build better systems, and think beyond just writing code.
It covers everything we talked about here and more - how to approach problems, structure your thinking, handle trade-offs, and actually enjoy system design.
Thanks for reading 💙
If you’re someone trying to level up your frontend skills - especially around system design - I hope this helped.
And if you’re preparing for an interview right now - you got this.
Top comments (4)
Hey it was a really good read. Would love to know more about how you tackled mobile performance because most of the times it's all good with desktop but mobile is what takes the hit. Anything that you think made the most impact for mobile performance, would love to hear.
Great article! I loved how thorough and detailed it is. Also, so damn relatable that system design being backend is a universal beginner assumption. 🛠️😆 On a side note, the cat cover image is so cute! 🐱✨
A very comprehensive and easy to understand guidelines for developers. Thanks for the book recommendation as well.
Hey, it was great to read this. Looking for tech services. visit : ajackus.com/