What 28,000 SKUs taught me about Bitrix
I walked into the project with a bias.
28,000 SKUs on Bitrix — that sounds like a recipe for suffering. N+1 queries in every iblock request. A sluggish product catalog. PHP doing things PHP shouldn't be asked to do at this scale. I'd made up my mind before writing a single line of code.
Three months later, I sent a message to a colleague: "Bitrix actually knows how to handle a catalog."
This isn't a sales pitch for the CMS. It's a breakdown of what I found inside — and why my assumptions were mostly wrong.
What I expected (and why I was wrong)
I came from the Next.js side of things. Bitrix, to me, meant old PHP, slow templates, and code that does everything in one file because why not. When I heard 28,000 products, I went straight into survival mode.
I expected slow iblock queries: Bitrix ORM can generate JOINs that look terrifying in SQL logs, and at 28k SKUs I assumed every catalog page would pull the whole table. I also expected no useful caching at the element level — figured I'd be building Redis layers from scratch on top of everything. And faceted filtering seemed borderline unrealistic at this scale in PHP.
The reality turned out to be more interesting than that.
How Bitrix actually handles a large catalog
Iblocks aren't just a product table. They're a system with separate entities for properties, pricing, warehouses, trade offers. It's complex — but the complexity is mostly deliberate.
The first surprise: Bitrix has a built-in caching layer for iblock queries. With the right configuration, it caches query results to file cache or memcached without any extra code. I didn't have to build that from scratch.
The second: HighLoadBlock — a separate mechanism for high-throughput tables. We moved price history and aggregated stock data there. A query that used to take 800ms started coming back in 90ms.
Third: multiple trade offers out of the box. Bitrix's product catalog natively handles variations by size, color, configuration — no need to invent a data model. It's there, and 1C syncs into it without custom field mapping.
I expected to build all of this myself. I didn't have to.
Three things Bitrix gets right
1C integration. On every project using a different CMS, I've watched teams spend months on 1C: custom APIs, data transformations, painful reconciliation loops. In Bitrix, that channel is built in. Products, prices, and stock levels come through the standard CommerceML protocol. We spent a week on configuration, not three months on custom integration work.
Access control per catalog section. With 28k SKUs across multiple categories, partner pricing tiers, and wholesale price lists, granular permissions matter. Bitrix handles this at the iblock level with user groups — no additional code. We configured three pricing tiers in a day.
Built-in search for moderate load. Before moving to Elasticsearch, we ran Bitrix's native search against 1,500 test queries. For a catalog without complex relevance tuning or synonyms, it held up. Elasticsearch became necessary only when no-results queries piled up and we needed fuzzy matching. Until that point, we didn't need it.
I'm not saying Bitrix is perfect. I'm saying it does these three things well — and for an e-commerce catalog, they're the right three things to do well.
Where headless helped (and where it didn't)
In a headless Bitrix setup, Next.js handles rendering while Bitrix serves as a REST API backend. The split creates deploy independence — frontend and backend can update on separate schedules.
Headless earned its place in two specific spots.
Deploy independence. While the backend was doing FTP deploys that took 40 minutes, the Next.js frontend deployed in 3. Bitrix patches didn't touch the front. The catalog page that used to clock 4.2 seconds on LCP was coming back in 1.4s after SSR + CDN.
ISR let us cache category pages and serve them from edge nodes. Bitrix became a clean API layer — 12 REST endpoints for catalog, search, and cart.
Where headless didn't add value: checkout. Conversion was at 3.8%, the client wasn't willing to risk a drop, and building a Next.js checkout would have added two months. We left it on Bitrix templates. That's not technical debt. It's an engineering decision.
What I'd do differently
We added HighLoadBlock too late. The first two months ran on standard iblocks for analytics and aggregated data. That created latency on reporting queries. Next time I'd pull aggregates into HighLoadBlock from day one.
Elasticsearch came in under deadline pressure, wired in parallel with the launch. It would have been cleaner to design the search layer upfront, not retrofit it. I'd start with ES from the beginning next time — not as an afterthought.
And I lost two weeks trying to work around the iblock cache, convinced it was broken. It wasn't. I was invalidating it wrong when 1C pushed updates. The Bitrix docs on cache tag invalidation aren't obvious, but once you understand the logic, it's straightforward.
Takeaway
28,000 SKUs on Bitrix isn't a problem to survive. It's an engineering project with a CMS that was built for this exact use case.
I came in biased toward cleaner frameworks. I left with a better read on what Bitrix is actually good at — and where you still need to add layers yourself.
Headless isn't a Bitrix replacement. It's a rendering and deployment layer that solves specific problems: slow LCP, deploy coupling, CDN caching. It adds complexity too — in API contracts, cache invalidation, and local dev setup. The question is always where each layer's responsibility ends.
At 28k SKUs, we found that line.