DEV Community

Nitin Sengar
Nitin Sengar

Posted on

From Invisible to Indexed: How Rebuilding My React App with Next.js Finally Got Google's Attention

There's a specific kind of frustration that only developers understand.

You've built something real. Something that works. Something people actually use. You open Google Search Console expecting to see growth — and you find a flatline. Pages you spent weeks building. Content you carefully structured. All of it, essentially invisible.

That was me, about a year into building SamanList.com.


It Started With a Grocery List

Not a startup idea. Not a hackathon project. A grocery list.

In many households — especially in India — the process of preparing a shopping list is surprisingly painful. You try to remember everything at once. You write quantities wrong. You forget whether you wanted 500 grams or a full kilogram. You forget the brand entirely. Then you send a voice note to your shopkeeper, they misunderstand half of it, and you still end up missing three things.

I wanted to fix that small, everyday frustration. So I started building a tool where users could prepare structured lists — with proper measure units, preferred brands, and shareable formats that could be sent directly to family members or local shopkeepers.

That everyday frustration became SamanList — a household list preparation tool where families can prepare, organize and share shopping lists directly with their shopkeeper.


Why React Made Perfect Sense at the Start

When I started, React was the obvious choice — and the right one.

The core of SamanList is interaction. Users are constantly selecting items, updating quantities, switching between units, filtering categories, remembering brand preferences. That kind of dynamic, stateful UI is exactly what React was built for.

I leaned heavily on useState to manage everything happening on screen — selected items, quantities, units, filters. Every interaction a user made triggered a state update, and React re-rendered only what needed to change. For a list-heavy app, that responsiveness felt like magic compared to traditional page reloads.

useEffect became my bridge to the outside world. Whenever a user opened a category, useEffect handled fetching the relevant items, syncing changes, and keeping the UI consistent with what was actually stored. It kept side effects — data loading, cleanup, subscriptions — cleanly separated from the rendering logic.

As the app grew more complex, useMemo saved me from myself. Filtering and sorting large lists on every render was quietly killing performance. Memoizing expensive calculations meant the app only recomputed what actually changed — not everything, every time.

And the component-based architecture was the real foundation. Lists, categories, quantity controls, unit selectors, sharing actions — each became its own independent, reusable piece. Building SamanList taught me component design in a way no tutorial ever had, because every decision had a real consequence I could immediately see.

React gave me a fast, interactive, well-structured application.

It just had one problem I didn't see coming.


The Problem Nobody Warns You About

A few months after launch, I started paying closer attention to analytics.

The app worked. Users who found it, used it. But finding it was the problem.

I opened Google Search Console and started digging — indexed pages, search impressions, crawl reports. The data told a story I didn't want to hear. Despite having dozens of list category pages — including grocery, household, and household electrical fittings, as well as kitchen essentials — almost none of them were being indexed properly. The ones that were indexed showed minimal impressions.

The content existed. The pages existed. But from Google's perspective, they were nearly empty.

Here's what was happening under the hood: React, by default, is a client-side rendering framework. When a crawler visited one of my list pages, it received a mostly bare HTML document — a root div and a bundle of JavaScript. The actual content — the list items, the category names, the descriptions — only appeared after the JavaScript downloaded, parsed, and executed in the browser.

Search crawlers can execute JavaScript, but it's inconsistent, deprioritized, and burns crawl budget. For a site with a growing number of pages, that inconsistency compounds fast. My carefully built pages were functionally invisible to the crawlers that mattered.

Worse, every page shared the same generic metadata. Same title. Same description. From a search engine's perspective, there was nothing to differentiate one list category page from another.

I had a React problem that React alone couldn't solve.


The Architecture Decision That Changed Everything

After researching the problem deeply, I landed on Next.js — and the migration turned out to be one of the most educational decisions of the entire project.

The philosophical shift Next.js forced was simple but profound: stop thinking about when your UI renders and start thinking about when your content becomes available.

The first major change was moving to file-based routing. In my React app, routing lived in JavaScript — a configuration file that mapped paths to components. It worked, but it was disconnected from the actual structure of the app. Next.js made routing a first-class part of the project structure itself. Each list category became a folder. Each page became a file. The URL structure and the project structure became mirrors of each other — cleaner to navigate, easier to scale, and far more meaningful to crawlers reading the site's architecture.

The second change was adopting Server-Side Rendering and Static Site Generation for my content pages. This was the core fix.

Instead of sending a bare HTML shell and waiting for JavaScript to fill it in, Next.js allowed me to pre-render my list pages with complete content already in the HTML — before it ever reached the browser. For category pages that didn't change constantly, I used Static Generation: pages were built once at deploy time and served instantly from a CDN. For pages that needed fresher data, SSR rendered the full HTML on each request, server-side, before sending it to the user or crawler.

The result was that when Google's crawler visited a SamanList category page, it received a fully formed HTML document — complete content, meaningful structure, everything readable without executing a single line of JavaScript.

The third change was metadata. Each page in Next.js could define its own unique title, description, and Open Graph tags — generated dynamically based on the content of that specific page. Grocery lists got grocery-specific metadata. Pharmacy lists got pharmacy-specific metadata. Every page finally had something distinct to say to a search engine.


What the Data Showed

The shift wasn't instant, but it was real.

Within a few weeks of migration, indexed pages climbed from a single page to over 15. Weekly search impressions started growing consistently rather than flatlining. Core Web Vitals — the performance scores Google uses as a ranking signal — went from failing to passing, largely because statically generated pages served from a CDN are dramatically faster than hydrating a JavaScript bundle.

More importantly, users started arriving from search. People who had never heard of SamanList were finding specific category pages through Google, exactly as intended.

The SEO improvement didn't come from keyword stuffing or backlink schemes. It came entirely from fixing the architecture — making content available at the right time, in the right format, with the right metadata.


What SamanList Is Today

SamanList — a smart grocery and household list sharing app has grown into a practical everyday planning tool for families and local shopkeepers.

Users prepare structured household and grocery lists with proper quantities and measure units, save preferred brands so they don't have to remember them every time, and generate clean shareable lists that can be sent directly through messaging apps to family members or local shopkeepers.

From the shopkeeper's side, receiving a structured list — instead of a voice note or a scribbled message — reduces mistakes, speeds up order fulfilment, and removes the back-and-forth of clarification.

The goal is the same as it was at the start: to make everyday tasks take less effort. If you want to try it, create and share your first shopping list on SamanList for free.


The Real Lesson

I started this project to learn React practically, and I did. But the deeper education came from the problems React alone couldn't solve.

React taught me how to build interfaces that feel alive — responsive, stateful, efficient. Next.js taught me that an interface nobody can find is an interface that doesn't exist. Analytics taught me that assumptions about user behaviour are almost always wrong until data proves otherwise.

The combination of building something real, measuring what actually happens, and improving based on evidence — that loop taught me more than any course or tutorial ever has.

If you're learning through building, keep going. The problems that frustrate you most are the ones that teach you the most.


Have you run into SEO challenges with a React app? I'd love to hear how you approached it — drop your experience in the comments.

Top comments (0)