Focusing on Frontend Web Development
In the past few years, I’ve tried multiple technologies, each focusing on two simple reasons:
- User experience as the main focus
- Interesting for me as a developer.
After working across the full stack for years, building backends in Node.js, setting up databases, configuring servers, and writing API endpoints, I found myself gravitating more and more towards the frontend. Not because backend work is less important, but because the frontend is where everything comes together for the person who actually matters: the user.
Why I Shifted Focus to Frontend
The shift was not sudden. It happened gradually as I noticed that the projects I was most proud of were the ones where I had spent the most time refining the user interface, the interactions, and the overall feel of the application. I could build the most elegant API in the world, but if the frontend was clunky, slow, or confusing, none of that backend elegance mattered to the end user.
In an article by Guillermo Rauch called Next for Vercel, he talks about a great reflection: **Applying (Amazon’s Bezo’s obsessive customer focus) to web development: “focusing on the frontend is the most customer-obsessive way to build your products” **. I think this is the perfect summary of user-focused web development.
That quote resonated with me deeply. Every interaction the user makes is with the frontend, the design, the way things render and works, the speed, the information, and what we want our brand to be perceived as is through the frontend. When a user opens your application, they do not see your database schema or your microservice architecture. They see colours, typography, layout, animations, and responsiveness. They feel speed or sluggishness. They experience delight or frustration. The frontend is the product as far as the user is concerned.
The Technologies That Shaped My Frontend Journey
My frontend journey has taken me through several frameworks and tools, each teaching me something different about building for the web.
React was the starting point. Learning React fundamentally changed how I think about user interfaces. The component model, the idea that you can compose complex interfaces from small, reusable pieces, felt natural and powerful. I spent months building projects with Create React App before moving on to more sophisticated setups.
Next.js was the next major step. Server-side rendering, static site generation, API routes, file-based routing, all of it felt like React had grown up. Next.js solved real problems I was facing: SEO, initial load performance, and the complexity of configuring webpack and Babel by hand. I built my original portfolio site with Next.js 14, and it served me well for years.
Remix challenged my assumptions about how web applications should work. Its philosophy of embracing web fundamentals, using HTML forms, leveraging HTTP caching, and respecting the browser’s native capabilities, was refreshing. I wrote about my experience building a full-stack application with Remix and a decoupled Express backend in another post, and the experience taught me a lot about the balance between framework magic and web platform fundamentals.
TailwindCSS changed my relationship with styling entirely. I was sceptical at first. Utility classes in the HTML felt wrong after years of writing clean, separated CSS. But after a week of using Tailwind on a real project, I was sold. The speed of iteration is remarkable. Instead of switching between files, naming classes, and managing specificity conflicts, I could design directly in the markup:
<div className="flex items-center gap-4 rounded-lg bg-gray-900 p-6 shadow-xl">
<h2 className="text-2xl font-bold text-amber-400">
Build faster, iterate quicker
</h2>
<p className="text-gray-300 leading-relaxed">
Utility-first CSS removes the friction between thinking
about design and implementing it.
</p>
</div>
The design-to-code feedback loop with Tailwind is incredibly tight, and when combined with a component-based framework like React, you get a system where the styling is co-located with the component logic, making refactoring straightforward and reducing the chance of dead CSS accumulating in your project.
Astro is the most recent addition to my toolkit, and it is the framework I used to rebuild my portfolio site. Astro’s “islands architecture” is brilliant in its simplicity: ship zero JavaScript by default, and only hydrate the interactive components that actually need it. For a content-heavy site like a portfolio or blog, this approach delivers outstanding performance without sacrificing the ability to use React components where interactivity is needed.
User Experience as the Driving Force
If we want to focus on user experience, we need to focus on minimising the time it takes for content to be available to the user and for interaction. The rest is secondary. The user should have access to the main functionality and content of the website as soon as possible. This is a very important way of improving the user’s satisfaction.
I think about user experience in layers. The first layer is speed: can the user see and interact with the content quickly? The second layer is clarity: can they understand what they are looking at and what they can do? The third layer is delight: does the experience feel polished, intentional, and enjoyable?
Modern frontend development gives us tools to address all three layers. Frameworks like Next.js and Astro handle the speed layer through server rendering and static generation. Design systems and component libraries help with the clarity layer. And animation libraries, thoughtful micro-interactions, and attention to detail handle the delight layer.
Performance: The Numbers That Matter
I think what Google is focusing on with PageSpeed Insights is a great example of where to focus. Metrics like First Contentful Paint (FCP), First Input Delay (FID), Largest Contentful Paint (LCP), and Cumulative Layout Shift (CLS) are great examples of focusing on the user experience. Take a look at Core Web Vitals for more information.
These are not abstract metrics. They directly correlate with user behaviour. Studies have shown that a one-second delay in page load time can result in a significant drop in conversions. Users are impatient, and rightfully so. When I optimise for Core Web Vitals, I am not chasing a score on a dashboard. I am making a real difference in how quickly someone can read an article, browse a portfolio, or complete a purchase.
Some of the patterns I have found most effective for improving performance include:
- Image optimisation: Using modern formats like WebP and AVIF, implementing responsive images with
srcset, and lazy-loading images below the fold. This alone can cut seconds off load times on image-heavy pages. - Font loading strategies: Self-hosting fonts and using
font-display: swapto prevent invisible text during load. Subsetting fonts to include only the characters you actually use can reduce font file sizes dramatically. - Code splitting: Loading JavaScript only when it is needed. In React, this means using
React.lazy()andSuspensefor route-based or component-based code splitting. - Minimising layout shift: Reserving space for images and dynamic content before they load, so the page does not jump around as elements appear.
// Lazy loading a heavy component to improve initial bundle size
import { lazy, Suspense } from "react";
const HeavyChart = lazy(() => import("./components/HeavyChart"));
function Dashboard() {
return (
<Suspense fallback={<div className="h-64 animate-pulse bg-gray-800 rounded-lg" />}>
<HeavyChart />
</Suspense>
);
}
This pattern is something I use regularly. By lazy-loading components that are not immediately visible or that require large dependencies, you keep the initial JavaScript bundle small and the first paint fast.
The Balance Between Frontend and Full-Stack
By saying this, I’m not minimising the importance of the backend. Backend development is essential for speed, state and data management, and stability.
For my products and for the services I want to provide to my customers, my main interest is in the frontend. I want to be able to give the users the best experience I can, so I will be focusing on improving my frontend skills.
Being a Full Stack Software Engineer means that you should be able to have skills in the frontend and in the backend but more important, on the way they interact with each other. My way of approaching this is to use “boring” and “proven” backend technologies and databases that offer my projects proven stability and performance at a low cost and focusing on optimising what the user sees and interacts with: frontend.
This is a deliberate strategy. I do not want to spend my time reinventing authentication flows or database connection pooling when there are battle-tested solutions available. PostgreSQL, Redis, Express, these are technologies that have been running in production for years. They work. They scale. They are well-documented. By choosing stable backend technologies, I free up my mental energy and development time to focus on the frontend, where the competitive advantage lies.
That said, understanding the backend is crucial even as a frontend-focused developer. Knowing how API endpoints are structured, understanding database query performance, and being able to reason about server-side caching all make you a better frontend engineer. You can make smarter decisions about data fetching, optimistic updates, and error handling when you understand what is happening on the other side of the network request.
Frontend Patterns I Keep Coming Back To
Over the years, a few patterns have proven their value across nearly every project I have worked on:
Component composition over configuration. Instead of building monolithic components with dozens of props, I prefer composing smaller, focused components together. This makes the code easier to understand, test, and modify:
// Prefer this composable approach
<Card>
<Card.Header>
<Card.Title>Project Name</Card.Title>
<Card.Badge variant="success">Live</Card.Badge>
</Card.Header>
<Card.Body>
<Card.Description>A brief project summary.</Card.Description>
</Card.Body>
<Card.Footer>
<Card.Link href="/portfolio/project">View Project</Card.Link>
</Card.Footer>
</Card>
Custom hooks for reusable logic. React hooks are one of the best abstractions in frontend development. Extracting logic into custom hooks keeps components clean and makes behaviour reusable across the application.
Progressive enhancement. Building the core experience with HTML and CSS first, then layering on JavaScript for interactivity. This ensures the application works even if JavaScript fails to load or takes a long time to execute, and it naturally produces more accessible and performant interfaces.
What Excites Me About the Future
The frontend landscape continues to evolve rapidly, and several trends have me particularly excited.
Server components, as pioneered by React and adopted by frameworks like Next.js, blur the line between server and client in a way that feels natural and powerful. The ability to fetch data and render HTML on the server while still having interactive client components in the same component tree is a significant advancement.
Edge computing is pushing rendering closer to the user. Platforms like Cloudflare Workers and Vercel Edge Functions allow us to run server-side logic at the edge, reducing latency for users around the world. I am particularly interested in how this changes the calculus for server-side rendering, when the server is a few milliseconds away instead of hundreds, SSR becomes even more attractive.
The web platform itself keeps getting more capable. Container queries, the :has() selector, view transitions, and the Popover API are all examples of capabilities that used to require JavaScript libraries but are now built into the browser. Every year, the platform reduces the amount of JavaScript we need to ship, and that is a win for everyone.
Browse my full portfolio to see my latest work.