Developing a Headless Architecture on 1C-Bitrix
The monolithic 1C-Bitrix architecture with templates and components worked well when the website was the only point of contact with customers. Today, the same catalog must be served to a mobile app, a PWA, voice assistants, and external aggregator services. Bitrix's component-based approach is not suited for this — it generates HTML, not JSON.
A headless architecture splits Bitrix into a backend (business logic, data, API) and an independent frontend. Bitrix becomes a headless CMS — managing content and data without generating HTML.
Architecture Diagram
[1C-Bitrix Backend]
├── Infoblocks (catalog, content)
├── Trade catalog (prices, stock)
├── CRM / Orders
└── REST API Layer
|
[API Gateway / nginx]
|
┌────┴─────────────┐
[React SPA] [Mobile App] [External Services]
Bitrix retains all business logic: order processing, sessions, shopping cart, authentication, 1C integration. The frontend is an independently developed and deployed React/Next.js application.
REST API in 1C-Bitrix
Bitrix does not have a built-in REST API comparable to Next.js or Laravel. The API is built in one of two ways:
1. Controllers via addAjaxAction (older but functional approach):
// /local/ajax/catalog.php
define('STOP_STATISTICS', true);
define('NO_KEEP_STATISTIC', 'Y');
define('BX_SECURITY_SHOW_MESSAGE', true);
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Origin: https://your-frontend.com');
CModule::IncludeModule('iblock');
$action = $_GET['action'] ?? '';
if ($action === 'catalog') {
$items = getCatalogItems($_GET);
echo json_encode(['status' => 'ok', 'data' => $items]);
}
2. Router via bitrix/routing (Bitrix 20+, recommended approach):
// local/routes/api.php
use Bitrix\Main\Routing\RoutingConfigurator;
return function(RoutingConfigurator $routes) {
$routes->prefix('api/v1')->group(function(RoutingConfigurator $routes) {
$routes->get('/catalog', [CatalogController::class, 'index']);
$routes->get('/catalog/{id}', [CatalogController::class, 'show']);
$routes->post('/cart/add', [CartController::class, 'add']);
$routes->post('/order', [OrderController::class, 'create']);
});
};
// local/controllers/CatalogController.php
class CatalogController extends \Bitrix\Main\Engine\Controller {
public function indexAction(int $page = 1, int $limit = 20): array {
$items = \Bitrix\Iblock\Elements\ElementCatalogTable::getList([
'filter' => ['ACTIVE' => 'Y', 'IBLOCK_ID' => CATALOG_IBLOCK_ID],
'limit' => $limit,
'offset' => ($page - 1) * $limit,
]);
return ['items' => $items->fetchAll(), 'page' => $page];
}
}
Authentication and Sessions
A headless architecture breaks Bitrix's standard session-based authentication. Two approaches:
JWT tokens. The user authenticates via the API, receives a JWT, and attaches it to each request. Bitrix validates the token and identifies the user:
// Middleware for JWT validation
function validateJwtToken(string $token): ?int {
$payload = JWT::decode($token, new Key(JWT_SECRET, 'HS256'));
return $payload->userId ?? null;
}
Cookie + CORS. Retain Bitrix's standard session mechanism but configure CORS for the frontend domain. Simpler to implement but more complex from a security standpoint (CSRF protection is mandatory).
API Response Caching
Without caching, a headless Bitrix installation is slow — every catalog request triggers a full database query. Multi-level caching:
// CDN cache for static catalog data (Redis + nginx)
public function indexAction(): array {
$cacheKey = 'catalog_page_' . $this->getCurrentPage();
$cache = Cache::createInstance();
if ($cache->initCache(3600, $cacheKey, '/catalog/')) {
return $cache->getVars()['data'];
}
$data = $this->buildCatalogData();
$cache->startDataCache();
$cache->endDataCache(['data' => $data]);
return $data;
}
The cache is invalidated when infoblock data changes via BXClearCache(true, '/catalog/') in the OnAfterIBlockElementUpdate event handler.
Deployment and CORS
Headless requires proper domain separation: api.yoursite.com (Bitrix) and yoursite.com (Next.js frontend on Vercel/nginx). nginx CORS configuration for the API server:
location /api/ {
add_header 'Access-Control-Allow-Origin' 'https://yoursite.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
add_header 'Access-Control-Allow-Credentials' 'true';
if ($request_method = 'OPTIONS') {
return 204;
}
fastcgi_pass php-fpm;
}
Headless on Bitrix is an architectural decision with tangible advantages (independent frontend, performance, multichannel delivery) and real costs (API development, caching, CORS, infrastructure). Make this decision deliberately, when the monolith has genuinely become a constraint — not because headless is fashionable.







