Intro
This day is a bit different from the previous ones. Initially, the idea was simple — one contract per day. But Web3 is not just about contracts and blockchain. There are other layers — UI, integration, the way everything connects together. At some point it became obvious: it makes more sense to start structuring the project early, instead of treating each part in isolation. As a developer who is getting close to an architect level — and someone who enjoys microservice architecture — I got curious: how are these projects actually structured?
A contract is just one piece. A dApp is a system. I assume the same principles apply here — some form of clean architecture, separation of concerns, clear boundaries. And for something like WishList Chain, it felt important to start thinking about the structure from the beginning.
At that point, I started thinking not just about the contract itself, but about the structure of the whole project. Because Web3 is clearly not only about writing smart contracts. There is always a frontend, some kind of interaction layer, maybe scripts or bots, and potentially even a backend later on. All of these parts are connected, whether you plan for it or not.
So the question became less about "what to build next" and more about "how to structure it properly from the beginning."
That's where the idea of using a monorepo came in.
Why Monorepo?
I decided to approach this a bit differently. Usually, I create separate repositories by responsibility (the "S" in SOLID), but not this time.
Here the picture is clearer. The contract and the frontend are tightly connected. Any change in the contract — new fields, updated logic, even a different address — will require changes in multiple places. That means more manual work, more context switching, and more chances to break something.
Better to keep things as simple as possible.
So instead of splitting things too early, I decided to keep everything in one place. A single repository, but clearly separated layers inside it:
wish-list-chain/
├── apps/
│ └── web/ ← Next.js 15
├── contracts/ ← Hardhat
├── package.json
└── .env
From a structural point of view, it already feels closer to a real system rather than a set of experiments.
I know this goes a bit against how I usually structure things. Normally, I prefer to separate repositories by responsibility — the "S" in SOLID. It keeps boundaries clear and makes scaling easier later. But in this case, it felt like the separation would introduce more friction than value. The responsibilities are still separated — just not at the repository level.
Project Stack
Before the code — a quick map of what we're working with and why.
| Tool | Role | .NET analogy |
|---|---|---|
| Next.js 15 (App Router) | Frontend framework | ASP.NET Core MVC |
| wagmi 2 | React hooks for blockchain | SDK wrapper for Web3 calls |
| viem 2 | Low-level Ethereum client | HttpClient for the blockchain |
| RainbowKit | Wallet connection UI | OAuth login button |
| @tanstack/react-query | Async state management | No direct equivalent |
| WalletConnect / Reown | Multi-wallet protocol | OAuth provider |
Theory — A Little Bit
wagmi sits on top of viem. viem handles the low-level blockchain calls. wagmi provides React hooks like useAccount, useReadContract, useWriteContract. You can drop down to viem when you need more control, but most of the time wagmi is enough.
RainbowKit is just a UI layer on top of wagmi — the modal, the button, the wallet list. It doesn't do any blockchain work itself.
What Clicked
Next.js 15 App Router makes everything a Server Component by default. wagmi hooks rely on React state and browser APIs — they can't run on the server. Any component that calls useAccount, useReadContract, or renders <ConnectButton /> needs 'use client' at the top. Otherwise, the code looks correct — but simply doesn't work.
ConnectKit doesn't support React 19 yet.
I actually started with ConnectKit — clean UI, good docs, everything looked straightforward. It failed immediately. Peer dependency error: it requires React 17 or 18, while Next.js 15 already ships with React 19. So that path just… stopped there.
This is the current state of the Web3 frontend ecosystem: some libraries are ahead, some are behind. Check React version compatibility before installing anything.
Downgrading React didn't feel right. So I kept React 19 and aligned the rest of the stack around it — wagmi 2.x ended up being the stable choice.
RainbowKit requires wagmi 2. wagmi 3 is out but RainbowKit hasn't released a compatible version yet. Pinning wagmi to version 2 for now. This will resolve eventually — until then, mixing versions breaks the dependency tree.
The Result
<ConnectButton /> renders. Click it — RainbowKit modal opens with MetaMask, WalletConnect, and others. Connect MetaMask — wallet address and balance appear.
That's a Next.js 15 app reading live data from the Sepolia blockchain through a connected wallet. No backend. No API. The blockchain is the data source.
Next: read totalDreamPower directly from the WishlistV3 contract using useReadContract.
Repo: github.com/alena-dev-soft/wish-list-chain
Stage: Dinosaur 🦕 — frontend connected. Blockchain is the backend.



Top comments (0)