Building Kuwait Drug Prices: Why We Moved from React to Astro

Finding the official listed price of a medicine in Kuwait should not be difficult. The information exists in price lists published by the Kuwait Ministry of Health, but a long document is not the easiest thing to search when you are standing in a pharmacy or checking a prescription on your phone.

That problem became Kuwait Drug Prices: an independent, bilingual directory for searching published retail and wholesale medicine prices in Kuwaiti dinars.

The project now contains 6,230 medicines from the 2026 list, preserves data from 2025, and lets people search in English or Arabic. It also provides a structured dataset and API for other tools. It is not a pharmacy, a medical service, or an official government website. It reports listed prices; it does not promise that a medicine is in stock or that every pharmacy will sell it at that exact price.

The site looks simple. Building it responsibly was not.

The first version: a React single-page app

The original version was built with React and Vite. That was a natural choice for the main experience: fast search, filters, cards, modals, dark mode, and a mobile-first interface all fit React well.

As an application, it worked. But the project was becoming more than an application.

Every medicine deserved a stable page with its name, strength, dosage form, pack, manufacturer, price, year, and source. We also wanted useful directory pages for brands, manufacturers, dosage forms, and A–Z browsing in both languages. Those pages needed real HTML, unique titles, canonical URLs, language alternatives, and sitemaps.

We initially generated SEO pages alongside the SPA. That approach worked in the narrow sense, but it created two parallel systems: one for the app and another for crawlable content. Routing, metadata, and templates were harder to reason about, and it was too easy for the two versions of the site to drift apart.

Why we moved to Astro

Astro matched the shape the project had grown into: mostly content and data pages, with a highly interactive search experience at the center.

The move gave us a simpler architectural boundary:

  • Astro generates the directory, medicine pages, informational pages, language variants, and sitemaps as static HTML.
  • React remains responsible for the interactive search interface, mounted as an island on the English and Arabic homepages.
  • Cloudflare Pages serves the static site, while small Pages Functions handle the API and MCP endpoints.

This was not a move away from React. It was a decision to use React where its interactivity is valuable and avoid shipping it where a static document is enough.

Astro also made the public shape of the site easier to understand. A medicine URL is now an actual generated page rather than an SPA route or a separately maintained prerendering artifact. Metadata lives beside the page that uses it. English and Arabic routes share layouts while still controlling direction, language tags, canonical URLs, and hreflang links explicitly.

The result is a site that works as both a fast search tool for people and a collection of durable documents for search engines, assistive technology, and other software.

The harder problem was the data

The framework migration was visible, but the more important work happened underneath it.

Medicine records from different yearly lists cannot safely be matched by name alone. Abbreviations change. Packs may be written as “1 Vial” in one place and “1 Vls” in another. Spacing and punctuation vary. Similar brand names can refer to different strengths or forms. A careless merge can show the wrong historical price on the wrong product—which is unacceptable for health-related information.

We introduced a versioned data model that separates medicine identity from yearly prices. A record now has structured fields for the brand, product name, strength, dosage form, pack, manufacturer, aliases, and stable identifiers. Each yearly price keeps its own provenance, including the source document, effective date, page, row, and file hash.

We also kept the old JSON view for compatibility instead of breaking existing consumers when the new model launched.

That led to the central lesson of the project: a trustworthy interface cannot repair an untrustworthy data pipeline. The UI can make evidence visible, but identity matching, normalization, and provenance have to be designed into the dataset itself.

How AI was used

AI was used during the development of this project as a coding and review assistant. It helped explore implementation options, draft and refactor code, identify edge cases, improve interface copy, and review areas such as accessibility, SEO, and build configuration. This blog post was also drafted with AI assistance and reviewed against the repository.

AI did not create the official medicine prices and is not treated as a source of truth. The price data comes from published source documents. AI-generated suggestions can be wrong, so important behavior is backed by code review, source references, deterministic transformation scripts, and automated checks. Medical categories are not inferred and presented as public claims, and the site does not use AI to give medical advice.

Being transparent about this matters, especially in a health-related project. “Built with AI” should not mean “trust the AI.” It should mean the assistance is disclosed, its limits are understood, and claims can still be traced to evidence.

Lessons we learned

1. Choose the architecture for the product you have now

The React SPA was not a mistake. It helped us build and learn quickly. The problem changed as the site grew into thousands of addressable pages. Astro became the better fit because the product had become a static directory with an interactive island, not because one framework is universally better than another.

2. Progressive migration is safer than a rewrite

Keeping the existing React search experience reduced both risk and scope. We could replace the page and routing layer without rebuilding the interaction model users already knew. Framework migrations are much easier when stable parts of the product are allowed to remain stable.

3. Static generation still has operational limits

Generating thousands of English and Arabic pages is straightforward until deployment constraints become part of the architecture. The build now checks the total file count against a Cloudflare safety budget. Search-index size is also capped after gzip compression. Performance budgets and platform limits are more useful when they fail the build than when they live in a checklist.

4. SEO is an information-architecture problem

Good metadata was only one part of the work. The larger improvement came from giving medicines, brands, manufacturers, dosage forms, and alphabetical indexes clear relationships and stable URLs. Sitemaps were split by purpose and language. Canonicals, alternate-language links, unique titles, and visible page content are generated together rather than patched onto an app afterward.

5. Bilingual support is more than translation

Arabic changes layout direction, labels, search behavior, navigation, and the way language alternatives are expressed to crawlers and assistive technology. Treating Arabic as a first-class route structure exposed decisions that would have stayed hidden if translation were only a final copywriting step.

6. Health data requires precise boundaries

The site must repeatedly distinguish a listed retail price from a pharmacy’s actual selling price, and price information from medical advice. It must not imply stock availability or government affiliation. In a health-related product, disclaimers are not enough; those boundaries have to shape labels, page hierarchy, data fields, and features we choose not to build.

7. Validate the output, not only the source code

The build checks that required routes and public files exist, every medicine page has a unique title and correct canonical URL, the expected current records are present, provenance fields are populated, and deployment budgets are respected. A successful compile does not prove that a data-heavy website is correct.

8. Preserve compatibility while improving the model

The project now exposes a versioned dataset and API, but the legacy data URL still works. Improving a public data model is easier when consumers have a migration path instead of a surprise.

Where the project is now

Today, Kuwait Drug Prices uses Astro 7 for static output, React 19 for the search island, Tailwind CSS for styling, and Cloudflare Pages and Pages Functions for hosting and server endpoints. It publishes human-readable pages as well as JSON data, API documentation, and machine-readable service descriptions.

There is still more to improve. Source lists change, identity matching remains careful work, Arabic search can always get better, and accessibility needs continuous testing. Trust is not a feature that can be marked complete after one release.

The biggest change was not replacing Vite pages with Astro files. It was learning to treat the project as a publishing system, a data pipeline, and a public reference—not only as a frontend application.

That perspective has made the codebase more deliberate and, more importantly, the information easier to verify.

Explore the project at kuwaitdrugprices.pages.dev.
Filter files

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

Technical Leadership vs. Managerial Leadership: Chart Your Career Path

Related Posts