Nuxt.js Frontend for 1C-Bitrix
Nuxt.js is a Vue framework with built-in SSR, the Vue-stack equivalent of Next.js. When a team or project has historically used Vue, Nuxt.js is the natural choice for a headless architecture on top of 1C-Bitrix. The principles are identical to Next.js: Bitrix serves data via REST API, Nuxt handles rendering. The implementation details differ.
Headless Bitrix + Nuxt: Key Differences from Next.js
Nuxt.js uses the Vue Composition API and its own data-fetching system (useAsyncData, useFetch). Routing is filesystem-based, similar to Next.js. SSR, SSG, and ISR (called "hybrid rendering" in Nuxt) are all 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, // render on the server
lazy: false,
}
);
const { data: products } = await useFetch('/api/catalog/products', {
query: { section: route.params.slug, limit: 24 },
key: `products-${route.params.slug}`,
server: true,
});
// SEO
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 on the server during SSR is not repeated on the client during hydration.
Nuxt Server Routes as a Bitrix Proxy
Nuxt 3 has a built-in H3 server with server routes (server/api/). This allows creating a proxy layer directly inside Nuxt without a separate backend service:
// 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,
},
}
);
// Normalize Bitrix data
return {
items: response.data.map(normalizeProduct),
total: response.total,
};
});
Nuxt server routes run on the Node.js server — Bitrix tokens never reach the browser, and CORS is not an issue.
State Management: 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 Vue 3 state manager. Simpler than Redux, integrates with Vue DevTools, supports SSR with hydration state.
Case Study: Nuxt.js for a Construction Portal
A construction services portal: contractor catalog (12,000 companies), ratings, reviews, tender module. Bitrix was used for content and user management. Vue was the frontend team's chosen stack.
Primary challenge: SEO for contractor pages (each is a unique company with unique content). SSG was not feasible due to frequent data updates; SSR with caching was the optimal approach.
Implementation:
-
Nuxt 3 with hybrid rendering: contractor pages — SSR + Redis cache (5 minutes); static pages (About, Terms) — SSG.
-
Nuxt server routes: proxy to Bitrix REST API with
useStorage('redis')cache from unstorage (bundled with Nuxt). -
Contractor search — Vue component with instant search via Typesense. When a company is updated in Bitrix, it triggers a webhook → a Node.js service updates the Typesense index.
-
Tender module — SPA inside Nuxt: application submission, review status, chat with the client. JWT authentication stored in an httpOnly cookie.
| Metric | Before (Bitrix template) | After (Nuxt.js) |
|---|---|---|
| TTFB (company page) | 1.2–1.8 s | 180–250 ms (cache) |
| Core Web Vitals (LCP) | 5.2 s | 1.8 s |
| Search engine indexing | Full (HTML) | Full (SSR) |
| New section development time | — | 40% faster (components) |
ISR Equivalent in Nuxt (SWR Cache)
Nuxt implements stale-while-revalidate via routeRules:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/catalog/**': { swr: 300 }, // 5-minute cache, background revalidation
'/company/**': { swr: 180 }, // 3-minute cache
'/about': { prerender: true }, // static generation
'/cart/**': { ssr: false }, // CSR only, no SSR
}
});
This is the Next.js ISR equivalent — pages are served from cache and updated in the background after expiry.
Deployment
Nuxt 3 supports multiple deployment targets: Node.js server, static export, edge functions (Cloudflare Workers, Vercel Edge). For a setup co-located with Bitrix on the same server — Node.js + PM2 + nginx.
# nginx: Nuxt on port 3000, Bitrix on port 80
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; }
}
Scope of Work
- Bitrix API design for Nuxt consumption
- Nuxt server route development (proxy + caching)
- Vue/Nuxt component development: catalog, product page, search, cart
- Hybrid rendering configuration: routeRules per page type
- Pinia stores: cart, authentication, wishlist
- Node.js + nginx deployment, PM2 cluster configuration
Timeline: comparable to Next.js — MVP 2–3 months, full project 4–6 months.







