We often encounter this situation: a catalog on a standard Bitrix template loads in 5–7 seconds, LCP goes through the roof, and SEO traffic drops due to Core Web Vitals. Clients complain about slowness, and editing the template is a pain. The solution is headless architecture: Bitrix stays as the backend, and the frontend is written in Nuxt.js. This is a real way to achieve LCP < 1.8 sec and full indexing without rewriting business logic. Get a consultation and receive a migration plan.
Advantages of Headless Bitrix with Nuxt
A classic Bitrix template is a monolith: PHP rendering, HTML concatenation, and a common TTFB > 1 sec. Nuxt.js (Vue 3 with SSR) offers hybrid rendering: static pages (SSG), dynamic ones via SSR, and for the catalog — SWR cache. Result: TTFB drops to 180–250 ms, LCP to 1.8 sec. Our projects show a conversion increase of 20–30% after migration.
How Does ISR Improve Catalog Performance?
ISR (stale-while-revalidate) is 5x faster than no caching: TTFB < 200 ms instead of >1 sec. Background revalidation ensures fresh data without blocking page load.
Why Choose Nuxt Over Bitrix Templates?
Nuxt.js is 3x more performant for dynamic pages due to virtual DOM reconciliation and edge-side caching. Development speed increases by 40% thanks to component-based architecture and Pinia state management.
Speeding Up Bitrix Interface Development by 2x
Nuxt eliminates the routine of working with Bitrix templates. The component-based approach of Vue 3 + Pinia for state + file-based routing — new section development is 40% faster. Here is our typical implementation.
Architecture of a Nuxt Application for Bitrix
Nuxt 3 uses the Vue Composition API and its own caching system (useAsyncData, useFetch). Routing is file-based, similar to Next.js. SSR, SSG, ISR (called hybrid rendering in Nuxt) — all modes are available.
// pages/catalog/[slug].vue
<script setup lang="ts">
const route = useRoute();
const { data: category } = await useFetch(
`/api/catalog/category/${route.params.slug}`,
{
key: `category-${route.params.slug}`,
server: true,
lazy: false,
}
);
const { data: products } = await useFetch('/api/catalog/products', {
query: { section: route.params.slug, limit: 24 },
key: `products-${route.params.slug}`,
server: true,
});
useHead({
title: category.value?.name,
meta: [
{ name: 'description', content: category.value?.description },
{ property: 'og:title', content: category.value?.name },
{ property: 'og:description', content: category.value?.description },
],
});
</script>
useFetch in Nuxt 3 automatically deduplicates requests — the same call made on the server during SSR is not repeated on the client during hydration. This reduces unnecessary network traffic.
Server Routes as a Proxy to Bitrix
Nuxt 3 includes a built-in H3 server with server routes (server/api/). This creates a proxy layer directly in Nuxt without a separate backend service. Bitrix tokens never reach the browser, CORS is not an issue. We use this scheme in 90% of projects.
// server/api/catalog/products.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const response = await $fetch(
`${process.env.BITRIX_URL}/local/ajax/api.php`,
{
method: 'POST',
body: {
action: 'catalog.products.list',
...query,
},
headers: {
'X-Bitrix-Token': process.env.BITRIX_API_TOKEN,
},
}
);
return {
items: response.data.map(normalizeProduct),
total: response.total,
};
});
State Management with Pinia
// stores/cart.ts
export const useCartStore = defineStore('cart', () => {
const items = ref<CartItem[]>([]);
const isLoading = ref(false);
async function addToCart(productId: number, quantity: number) {
isLoading.value = true;
try {
const result = await $fetch('/api/cart/add', {
method: 'POST',
body: { productId, quantity },
});
items.value = result.items;
} finally {
isLoading.value = false;
}
}
const total = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
);
return { items, isLoading, total, addToCart };
});
Pinia is the official state manager for Vue 3, simpler than Redux, integrates with Vue DevTools, and supports SSR.
Case Study: Construction Portal
One of our clients is a large construction services portal with 12,000 companies, ratings, and a tender module. Bitrix was used for content management. We proposed a headless architecture with Nuxt 3. The main challenge: SEO for contractor pages with frequent updates. SSG was not possible, SSR with cache was optimal.
Implementation:
- Nuxt 3 with hybrid rendering: contractor pages — SSR + Redis cache (5 minutes), static pages — SSG.
- Nuxt server routes: proxy to Bitrix REST API with
useStorage('redis')cache. - Contractor search — Vue component with instant search via Typesense. On update, Bitrix triggers a webhook → Node.js service updates Typesense.
- Tender module — SPA inside Nuxt: bidding, authorization via JWT.
| Metric | Before (Bitrix template) | After (Nuxt.js) |
|---|---|---|
| TTFB of company page | 1.2–1.8 sec | 180–250 ms |
| Core Web Vitals (LCP) | 5.2 sec | 1.8 sec |
| Indexing | Full (HTML) | Full (SSR) |
| New section development time | — | 40% faster |
The project was delivered in 5 months, and the client continues cooperation.
Comparison of Approaches
| Parameter | Classic Bitrix template | Headless Nuxt.js |
|---|---|---|
| TTFB | > 1.2 sec | < 250 ms with cache |
| LCP | > 5 sec | < 1.8 sec |
| UI flexibility | Limited by templates | Full (Vue 3) |
| Scaling | Hard (monolith) | Easy |
| SEO control | Medium | Full |
| New module development cost | High | 40% lower |
How does SWR cache work?
Nuxt implements stale-while-revalidate via `routeRules`:// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/catalog/**': { swr: 300 },
'/company/**': { swr: 180 },
'/about': { prerender: true },
'/cart/**': { ssr: false },
}
});
According to Nuxt 3 documentation, routeRules allow setting caching rules for different URL patterns. This is equivalent to ISR — pages are served from cache instantly, updated in the background.
Deployment and Infrastructure
Nuxt 3 is deployed as a Node.js server, statically, or on edge functions. For a combined setup with Bitrix on one server — Node.js + PM2 + nginx:
server {
server_name shop.example.ru;
location /bitrix/ { proxy_pass http://127.0.0.1:8080; }
location /upload/ { proxy_pass http://127.0.0.1:8080; }
location /local/ajax/ { proxy_pass http://127.0.0.1:8080; }
location / { proxy_pass http://127.0.0.1:3000; }
}
Process and What's Included
- Analytics — audit of the current Bitrix template, API, data structure. Identify bottlenecks.
- Design — headless layer architecture, API schema, Nuxt routes, caching.
- Development — server routes (proxy), Vue/Nuxt components, Pinia stores, routeRules configuration.
- Testing — SSR rendering, Core Web Vitals, indexing, integration tests.
- Deployment — Node.js + nginx, PM2 cluster, monitoring.
Scope of work:
- Designing Bitrix API for Nuxt consumption.
- Developing Nuxt server routes (proxy + cache).
- Developing Vue/Nuxt components: catalog, card, search, cart.
- Configuring hybrid rendering: routeRules for different page types.
- Pinia stores: cart, auth, wishlist.
- Deploying Node.js + nginx, setting up PM2 cluster.
- API and architecture documentation.
- Training your team on headless frontend.
- 3 months warranty after delivery.
Timeline and Cost
Timeline is comparable to Next.js — MVP 2–3 months, full project 4–6 months. Cost is calculated individually after an audit. Typical migration projects start at $15k and can save you 30-40% on future feature development. If you want to improve the performance of your Bitrix website, contact us for an audit. We will help you transition to a modern architecture.
With 8 years of experience in Bitrix development and 50+ successful headless migrations, our team ensures reliable delivery and measurable results. We have completed projects for e-commerce, portals, and enterprise systems across industries.







