Next.js Frontend for 1C-Bitrix
The Bitrix PHP monolith handles 80% of requirements. The remaining 20% — high-traffic pages, SEO for dynamic content, PWA, personalization with edge computing — require a different architecture. Next.js as a frontend layer on top of the Bitrix backend is the headless approach: Bitrix manages content and business logic, Next.js handles rendering.
This is not a replacement for Bitrix, but a separation of concerns: Bitrix is the reliable backend for e-commerce (orders, catalog, CRM, payments); Next.js is the modern frontend with SSR, SSG, ISR, and strong Core Web Vitals.
Headless Bitrix + Next.js Architecture
Bitrix acts as an API server. REST controllers are developed on the Bitrix side using \Bitrix\Main\Engine\Controller or custom endpoints under /local/ajax/.
Next.js runs on a separate server (Node.js), consumes the Bitrix API, and renders pages. Between them sits an API layer.
Browser → Next.js (SSR/SSG) → Bitrix REST API → DB
↓
Redis Cache
Typical request flow:
// next.js: getStaticProps for a category page
export async function getStaticProps({ params }) {
const [category, products] = await Promise.all([
fetchBitrix(`/api/catalog/category/${params.slug}`),
fetchBitrix(`/api/catalog/products?section=${params.slug}&limit=24`),
]);
return {
props: { category, products },
revalidate: 300, // ISR: regenerate after 5 minutes
};
}
Incremental Static Regeneration (ISR) is the key Next.js feature for e-commerce: pages are generated statically on first request and regenerated in the background on a schedule. This delivers the speed of static files with the freshness of dynamic content.
API on the Bitrix Side
Building a clean REST API on top of Bitrix without unnecessary dependencies:
// /local/php_interface/include/api/catalog/ProductsController.php
class ProductsController extends \Bitrix\Main\Engine\Controller
{
public function getListAction(
string $section = '',
int $page = 1,
int $limit = 24,
string $sort = 'NAME',
string $order = 'ASC'
): array {
$filter = ['ACTIVE' => 'Y', 'IBLOCK_ID' => CATALOG_IBLOCK_ID];
if ($section) {
$sectionId = $this->getSectionIdBySlug($section);
$filter['SECTION_ID'] = $sectionId;
$filter['INCLUDE_SUBSECTIONS'] = 'Y';
}
$result = \CIBlockElement::GetList(
[$sort => $order],
$filter,
false,
['nPageSize' => $limit, 'iNumPage' => $page],
['ID', 'NAME', 'DETAIL_PAGE_URL', 'PREVIEW_PICTURE',
'PROPERTY_BRAND', 'CATALOG_PRICE_1']
);
$products = [];
while ($el = $result->GetNextElement()) {
$products[] = $this->formatProduct($el);
}
return [
'items' => $products,
'total' => (int)$result->SelectedRowsCount(),
'pages' => ceil($result->SelectedRowsCount() / $limit),
];
}
}
The API must return normalized data, not raw Bitrix structures with noise fields like ~PREVIEW_TEXT and IBLOCK_ELEMENT_ID.
SSR for SEO-Critical Pages
Product pages, category pages, blog articles — candidates for SSG/ISR. Cart, checkout, account — CSR (client-side rendering), SEO is not required.
// Dynamic path generation for products
export async function getStaticPaths() {
const products = await fetchBitrix('/api/catalog/products/slugs');
return {
paths: products.map(p => ({ params: { slug: p.slug } })),
fallback: 'blocking', // new products render on first request
};
}
fallback: 'blocking' allows new products to be served without a full site rebuild.
Case Study: Next.js Frontend for a Fashion Retailer
A clothing retail chain, online catalog of ~35,000 SKUs, seasonal restocks. Problem: Core Web Vitals LCP = 4.8 s (target < 2.5 s), the Bitrix template was heavy and slow on mobile.
Bitrix was kept as the backend: product management, orders, CRM, 1C integration. A Next.js frontend was developed on top.
Implementation:
-
Bitrix API: controllers for products, categories, brands, search, and cart (SSR-compatible via cookie session).
-
Next.js App Router (Next.js 14): Server Components for SEO pages, Client Components for interactive elements (filters, cart, authentication).
-
Images:
next/imagewith automatic optimization, WebP, responsive srcset. Image hosting via CDN (separate from Bitrix). -
Search: Meilisearch with an index fed from Bitrix, React instant-search component.
-
Cart: state in Zustand + synchronization with the Bitrix cart via REST API on every change.
| Metric | Bitrix template | Next.js |
|---|---|---|
| LCP | 4.8 s | 1.4 s |
| CLS | 0.18 | 0.02 |
| FID / INP | 280 ms | 45 ms |
| PageSpeed Mobile | 34 | 82 |
| TTFB (category) | 820 ms | 180 ms (ISR cache) |
The migration took 4 months: 1 month on the Bitrix API, 3 months on the Next.js frontend. The old template remained live in parallel; the cutover was a DNS switch taking under a minute.
Cart State Management in Next.js
The cart is a complex case in headless architecture: it must work before authentication, sync with Bitrix upon login, and not be lost during page navigation.
Solution: a guest_token in a cookie; the cart is stored in Bitrix under this token. Upon login — merge the guest cart with the user's cart. React state is only a UI mirror of the server-side cart.
Deployment and Infrastructure
Next.js is a Node.js application requiring a dedicated process. Options: Vercel (simplest, but data crosses borders), VPS/dedicated with PM2 + nginx, Docker container.
Nginx as a reverse proxy in front of Next.js and Bitrix:
# Static and SEO pages → Next.js
location / {
proxy_pass http://nextjs:3000;
}
# REST API → Bitrix
location /api/bitrix/ {
proxy_pass http://bitrix/local/ajax/;
}
# Admin panel → Bitrix
location /bitrix/ {
proxy_pass http://bitrix;
}
Scope of Work
- API design: endpoints, data schema, caching strategy
- REST controller development in Bitrix
- Next.js application development: routing, SSG/ISR/SSR, components
- Cart, authentication, and checkout integration with Bitrix
- CDN setup for images, nginx-level caching
- Deployment, monitoring, CI/CD
Timeline: MVP (catalog + product page + search) — 2–3 months. Full frontend with cart, checkout, and account — 4–6 months.







