Skip to content
All articles
Development8 min

Nuxt, Next.js, Rust: why we change our stack, and when not to

In four years our main frontend framework changed once, and our own product, Damka, was rewritten three times. From the outside that looks like chasing trends. From the inside every decision had a reason, and I wouldn't repeat all of them.

Azamat AbduyaminovFounder, lead engineer

Every six months someone on the team brings in a new framework and says everything will be faster with it. Sometimes they're right. Usually they're not. I want to describe how we actually made our stack decisions, and where we honestly got it wrong.

The short version: on client websites the stack changes rarely and only for a solid reason. We experiment on our own products, where we pay for our own mistakes.

2023–2024: almost everything on Nuxt 3

When the studio started taking on bigger projects, we settled on Django + Nuxt 3. That's what Mening Yurtim (MY5), Legal Alliance, PlanBaby, UZBCONTENT, Japanese Garden, IBN Express and the TV channel landing pages are built on.

Why Vue and Nuxt? Vue templates read almost like plain HTML, so new people on the team get up to speed faster. SSR works out of the box, and for TV channels and law firms search traffic matters. Django gave us a ready-made admin that clients learned in a day.

I still think it was the right call for its time. We've maintained MY5 since 2023, it has more than 140 commits, and it runs happily on the same stack.

Not everything was smooth, though. Nuxt 3 reached a stable release at the end of 2022, and for the first few months some of the modules we relied on hadn't been ported yet. Some things we did by hand, some we waited for. That was the price of getting in early, and I think we paid it knowingly.

Frontend stack across our portfolio projectsprojects
Nuxt 3 (2023–2024)
9
Next.js (2025–2026)
6
React + Vite (2026)
3

The numbers are counted from the projects listed on our site. Bots and mobile apps aren't included.

2025: why we moved to Next.js

The switch didn't happen overnight. There were three reasons, and none of them is "Next.js is better than Nuxt".

People. Tashkent has noticeably more React developers than Vue developers. Any search on hh.uz or in the Telegram job channels shows it.

Libraries. Packages for internationalisation (next-intl), forms and analytics come out for React first. Enlawyer needed three languages, structured data and a sitemap per locale, and for React all of that already existed.

AI assistants. It sounds odd, but it's a real factor. Assistants write React and Next.js code with much more confidence than Nuxt code, because they were trained on far more examples. For a small studio that's hours every week.

Since then we've built Enlawyer, Excellent Print, Mezon Ta'lim and Xina Soliha on Next.js. The last two are already on Next.js 16.

The switch wasn't free. The App Router and React Server Components work differently from what we were used to in Nuxt, and our first Next.js projects moved slower than usual. We redid the same things several times before we understood where the line between server and client code sits. And now the studio runs two frontend stacks at once: the old Vue sites haven't gone anywhere, and we still have to be able to maintain them.

Damka: three versions in two years

This is where I made the most mistakes, and that's fine, because Damka.uz is our own product: an online platform for Russian checkers.

The first version, in 2024, was Django and Nuxt: games, rooms, everything over ordinary HTTP requests. It worked, but it's not enough for a live game between two people.

The second version moved to Django Channels and WebSockets, with Nuxt 4 on the front. It added an AI opponent using negamax with alpha-beta pruning, ELO ratings, matchmaking and spectator mode. That's where we hit Python's limits: move search is pure CPU work, and the deeper the bot calculates, the longer the player waits.

The third version is a game engine in Rust (actix-web, WebSocket) with neural-network position evaluation. The front is React, the admin is Next.js, plus a Telegram bot that lets people play right inside group chats and run tournaments under IDF rules.

Damka.uz Russian checkers platform
Damka.uz: the third version, with the Rust engine

Was it worth it? For the engine, yes. But I underestimated the cost. Every rewrite meant months in which users got zero new features. If I'd separated the engine from the web part from the start, only the engine would have needed rewriting, not the whole product.

Shajara: Fastify instead of Django

Shajara is our family-tree startup, where several relatives edit the same tree at the same time. It's real-time, and we could have built it on Django Channels, but we chose Fastify 5, Drizzle ORM and PostgreSQL, with React 19 and Vite on the front and syncing over Socket.IO.

The main reason: one language. TypeScript types flow from the database to the component, so when the structure of a tree node changes, the build breaks instead of production. The tree itself is drawn with d3, sign-in is via Google, and the interface is in Uzbek, Russian and English. For a product with complex, nested data, that saved more time than any framework speed could.

I wouldn't do this on client projects yet. Django, with its admin, remains our main backend. Fastify is a tool for one specific job.

The boring technology rule

Here's our internal principle. I put it into words after the second Damka rewrite.

“A client project is not a place for experiments. New technology goes through our own product first, and only after we've lived with it for six months without surprises does it make it into client work.”
Azamat Abduyaminov — founder of Idrok Group

In practice: Rust lives only in Damka. Fastify lives only in Shajara. A client who orders a corporate website gets Django and Next.js, proven on a dozen projects.

What never changed

Looking at everything above, it's easy to conclude we switch technologies every year. But most of the stack hasn't changed at all in four years. PostgreSQL in every project that has a database. Redis for caching and queues. Celery for background jobs: broadcasts, reports, image processing. Docker and GitLab CI for deploys. nginx in front of it all.

The bots live on the same aiogram too. We move old aiogram 2 projects to version 3 only when we're opening the code for some other reason anyway. Rewriting a working bot for a new library version makes no sense if it's taking orders and nobody is complaining.

That unchanging part is exactly what lets us experiment with the rest. When the database, deploys and monitoring are the same everywhere, switching frontend frameworks means replacing one layer, not the whole project.

Before you change your stack

If you lead a team or are choosing a contractor, these are the questions I ask myself every time. If most answers are "no", the stack stays as it is.

  • There's a concrete problem the current stack can't solve (not "it's awkward", but genuinely can't)
  • We can hire people for the new stack in Tashkent at a reasonable cost
  • We try the new stack on our own project first, not a client's
  • We've estimated how many weeks the switch takes and what users get in that time
  • Old projects keep working without a rewrite
  • Someone will be around to maintain it three years from now

If I had to name what I'd do differently: split the Damka engine from the web app in version one and skip version two entirely. The move from Nuxt to Next.js I'd repeat exactly as it went, gradually and without rewriting anything old.

Got a task? Message us — let’s talk.

Write on Telegram directly to the studio’s founder. Describe what you need in a couple of lines — we’ll reply with questions and a rough estimate.