I Built Prishunden.se
I’ve built Prishunden.se, a Swedish price comparison platform focused on PC hardware.
And to be clear, it is not finished.
It is a work in progress, it will keep evolving, and it is exactly the kind of project that probably never feels truly complete.
On the surface, it looks pretty simple. Search for a product, compare prices from Swedish retailers, check stock status, look at historical pricing, click through, done.
Underneath, it is one of the most technically dense projects I’ve built.
This was not a case of throwing together a frontend and calling it a day. Prishunden.se forced me to build a full data pipeline with scraping, normalization, product matching, background jobs, admin tooling, content systems, SEO, and production infrastructure.
That is exactly why I’m proud of it.
It also means the project has a long runway ahead of it. The current version is real, usable, and already technically complex, but I see it as a foundation for something much bigger.
What it is
Prishunden.se is a price comparison site for Swedish PC hardware and computer components.
The goal is simple from a user perspective: make it easier to understand what a part actually costs right now, where it is in stock, and whether different retailer listings are actually the same product.
That last part is where projects like this stop being “just a website”.
In this space, naming differences matter. One retailer might include the full manufacturer model name, another might trim it, a third might format the MPN differently, and a fourth might omit key identifiers entirely. If the system matches products badly, the whole value of the site drops immediately.
So the real work is not just showing prices. It is building enough structure behind the scenes that the data is worth trusting.
Why it was challenging
The hard part was that every layer had real complexity.
Retailer data is inconsistent. Brand data is inconsistent. Images are inconsistent. Some sources are straightforward to ingest, others need browser automation, custom extraction logic, or extra handling when the source is slow, protected, or just badly structured.
Then there is the matching problem.
If multiple stores list the same GPU, monitor, motherboard, or SSD, the system has to understand that they belong to one canonical product instead of creating fragmented duplicates. That means using identifiers like EAN and MPN when they exist, but also building around the reality that they are not always clean or complete.
It also means building safeguards. A price comparison engine can’t afford aggressive matching that quietly merges the wrong products together.
The stack
Prishunden.se is built as a TypeScript monorepo with a separate web app, worker app, and shared packages.
const stack = {
frontend: "Next.js 16 + React 19",
styling: "Tailwind CSS 4",
language: "TypeScript 6",
database: "MySQL + Prisma",
queueing: "BullMQ + Redis",
scraping: "Playwright + Cheerio",
tooling: "pnpm workspaces + Turbo",
runtime: "Docker Compose for services and full-stack runs",
};At a repo level it is split roughly like this:
apps/web -> public site, API routes, admin UI
apps/worker -> scrapers, ingestion jobs, background processing
packages/db -> Prisma schema, migrations, DB utilities
packages/logger -> structured loggingThat separation mattered a lot. Scraping and background processing live in their own worker instead of being squeezed awkwardly into the web app, which made the whole platform easier to evolve.
How it works in practice
The public site is just the last step in a much bigger system.
1. Data ingestion
The worker collects product and price data from multiple sources.
Some sources are easy to parse. Some need custom scrapers. Some are HTML-heavy. Some require browser-based handling. I built the worker to support multiple ingestion patterns rather than pretending every source behaves the same way.
2. Normalization and matching
After ingestion, the raw source data has to be normalized before it becomes useful.
That means cleaning identifiers, normalizing MPNs, reconciling brand naming, and deciding whether a record belongs to an existing product or should create a new canonical product.
This is the core of the project. The matching layer is what turns scraped retailer listings into an actual product catalog.
3. Product and price storage
The cleaned data ends up in MySQL through Prisma models and migrations.
That gives me stable product entities, retailer listings, and historical pricing instead of a temporary scrape dump. It also gives the public site a solid foundation for product pages, search, filtering, and trend visibility.
4. Background jobs
A lot of work happens asynchronously:
- scraping and import runs
- cleanup and integrity jobs
- image downloads and transformations
- content and article workflows
- catalog maintenance tasks
BullMQ and Redis are what make this feel like a system instead of a collection of scripts.
5. Public site and admin tooling
The public-facing part includes product pages, category pages, search, blog content, and SEO-focused rendering.
The internal part matters just as much. I built admin tooling for moderation, content management, quality review, unmatched catalog work, and operational control. Real-world data systems need oversight, and I wanted the platform to include that from the start rather than bolt it on later.
The parts I’m most proud of
Product matching
This is the biggest one.
Displaying price cards is the easy part. Building a system that tries to understand whether multiple retailer records refer to the same real-world product is where the engineering challenge actually starts.
That work touches identifiers, normalization rules, source quirks, and quality safeguards. It is also the reason the site can be genuinely useful instead of just noisy.
The worker architecture
I treated scraping and ingestion like a real application, not a side script.
That meant a dedicated worker app, queue-driven processing, reusable utilities, and enough operational structure that I can actually maintain and extend it over time.
The image pipeline
Product images turned out to be a bigger problem than they look.
Rather than relying blindly on third-party image URLs, I built a dedicated image pipeline with download strategies, validation, format handling, and generated variants. That gives me better control, better caching behavior, and fewer surprises when source sites change.
The internal workflows
One thing I care about in larger projects is whether they include tools for their own edge cases.
Prishunden.se has internal workflows for unmatched products, data quality issues, moderation, and operational admin work. That is invisible to most users, but it is exactly what makes a complex system maintainable.
It is not done, and that is part of the point
One thing I like about projects like this is that they are never really “completed” in the traditional sense.
There is always another source to integrate, another matching edge case to solve, another quality workflow to tighten, another performance bottleneck to remove, another category to open up, and another internal tool that would make the system better.
That is not a flaw in the project. It is part of what makes it interesting.
Prishunden.se already does a lot, but it is still very much a living system.
Where I want to take it next
Right now the site is centered on Swedish PC hardware, but I absolutely plan to expand it into more categories over time.
That expansion is not just about adding more pages. It means extending the catalog model, broadening the ingestion layer, adding more matching rules, and making sure the quality bar stays high as the scope increases.
That is one of the reasons I built the architecture the way I did. I did not want something that only works for the current snapshot of the project. I wanted a system that can keep growing.
The less glamorous engineering mattered just as much
A project like this is easy to describe in terms of the flashy bits: scraping, search, prices, dashboards.
But a lot of the real work was in the boring details:
- strict TypeScript across the monorepo
- Prisma schema discipline and migrations
- structured logging
- auth and RBAC for admin features
- rate limiting on public-facing APIs
- host-dev versus full compose runtime modes
- deploy validation across lint, type-check, tests, and builds
None of that is exciting in a screenshot, but it is the difference between a demo and a platform that can keep growing as I expand it.
What I learned
The biggest lesson was that building a niche data product is mostly about building trust.
Users do not care how interesting the architecture is if the catalog is wrong, the prices are stale, or the product matching is unreliable. So the technical challenge is not just data collection. It is building enough validation, structure, and operational discipline around the data that the output becomes trustworthy.
It also reminded me how much I enjoy projects that force me across multiple layers of engineering:
- frontend UX
- backend APIs
- database design
- scraping and automation
- queue-driven workflows
- SEO and content rendering
- infrastructure and deployment
- internal tooling
Prishunden.se touched all of them.
Why I’m proud of it
This project has real moving parts.
It is not a landing page. It is not a tutorial clone. It is not a basic CRUD app dressed up with nicer styling.
It is a Swedish hardware price comparison platform with scraping infrastructure, product matching, price history, background processing, admin systems, content workflows, and a production-minded architecture holding it together.
That kind of build teaches you different lessons than simpler apps do.
And honestly, that is why I wanted to write about it.
Prishunden.se represents the type of software work I enjoy most: messy real-world inputs, strong technical constraints, system design problems, and a product that people can already use while it continues to grow.
I didn’t just build pages.
I built the machinery behind them, and I’m still building it.