Bitrix Caching: Install, Source and Security | FunnelSlayer

Bitrix Caching

Published by bxmaximum in bitrix-framework-skills

No known issues132 installs

What this skill does

Covers caching in Bitrix — Cache (unmanaged), ManagedCache, TaggedCache, ORM auto-cache, component cache via startResultCache/endResultCache, Composite Site, cache engine configuration (files, memcached, redis) in .settings.php. Applied when optimizing performance, invalidating by tags and events, setting TTL, cache warm-up, and debugging cache hits. Key terms — cache, invalidate, TaggedCache, ManagedCache, startResultCache, cacheDir, clean.

Add Bitrix Caching to your agent

Review the source and files first. When you are ready, copy the prompt instruction or use the CLI command supported by your environment.

Install with a prompt

Paste this into a compatible coding agent:

add this skill "bitrix-caching" from https://github.com/bxmaximum/bitrix-framework-skills

Install with the CLI

Run this command in a controlled environment after reviewing the repository:

npx skills add https://github.com/bxmaximum/bitrix-framework-skills --skill bitrix-caching

Skill instructions

Caching in Bitrix

Cache Levels

  1. Unmanaged Cache (Bitrix\Main\Data\Cache) — with TTL, key, and path. Cleared automatically by TTL and manually.
  2. Managed Cache (ManagedCache) — lives until explicit invalidation, convenient for "rarely changing" data.
  3. Tagged Cache (TaggedCache) — keys are grouped by tags; invalidating one tag clears all associated entries.
  4. ORM Cache — automatic: isCacheable() in the tablet + ['cache' => ['ttl' => ...]] in getList.
  5. Component Cache — via startResultCache() / endResultCache() and parameters CACHE_TYPE, CACHE_TIME, CACHE_GROUPS.
  6. Composite Cache — HTML cache of the entire page (Bitrix\Main\Composite\Engine).

Configuration in .settings.php

'cache' => [
    'value' => [
        'type' => [
            // 'class_name' => \Bitrix\Main\Data\CacheEngineRedis::class, // one of these
            'type' => 'redis',     // files|memcache|redis|apc|xcache|none
            'host' => '127.0.0.1',
            'port' => 6379,
            'serializer' => \Redis::SERIALIZER_IGBINARY,
        ],
        'sid' => 'PROJECT_',       // key prefix
        'cache_flags' => [
            'config_options' => 3600,
            'site_template' => 3600,
            'iblock_include' => 3600,
        ],
    ],
    'readonly' => false,
],

Different sections (config_options, menu, site_template, etc.) define TTL for internal kernel caches.

Unmanaged Cache Template

$cache = \Bitrix\Main\Data\Cache::createInstance();
$ttl = 3600;
$cacheId = 'posts_list_' . md5(serialize($filter));
$cacheDir = '/vendor_blog/posts';

if ($cache->initCache($ttl, $cacheId, $cacheDir))
{
    $data = $cache->getVars();
}
elseif ($cache->startDataCache())
{
    $data = PostTable::getList([
        'filter' => $filter,
        'select' => ['ID', 'TITLE'],
    ])->fetchAll();

    // If conditions are not met — stop writing cache:
    if (empty($data))
    {
        $cache->abortDataCache();
    }
    else
    {
        $cache->endDataCache($data);
    }
}
  • cacheId — unique key, includes all variables affecting the result.
  • cacheDir — cache "folder"; convenient to clear by directory $cache->cleanDir($cacheDir).

Managed Cache

$managed = \Bitrix\Main\Application::getInstance()->getManagedCache();

if ($managed->read(86400, $cacheId, 'posts'))
{
    $data = $managed->get($cacheId);
}
else
{
    $data = $this->fetchExpensive();
    $managed->setImmediate($cacheId, $data); // or set() — write at the end of request
}

// Invalidation:
$managed->clean($cacheId, 'posts');
$managed->cleanDir('posts');

Tags

use Bitrix\Main\Application;

$taggedCache = Application::getInstance()->getTaggedCache();

$taggedCache->startTagCache('/vendor_blog/posts');
$taggedCache->registerTag('posts_list');
$taggedCache->registerTag('post_42');
$taggedCache->endTagCache();

// Tag invalidation — clears all entries registered under this tag:
$taggedCache->clearByTag('posts_list');

Use your own tag names for HTML/component caches. There are no automatic TaggedCache tags like ORM_<TABLE_NAME>.

ORM Query Cache

PostTable::getList([
    'select' => ['*'],
    'filter' => ['=ACTIVE' => 'Y'],
    'cache'  => [
        'ttl' => 3600,
        'cache_joins' => true, // cache JOIN queries
    ],
]);

ORM auto-cache is stored under ManagedCache directories orm_<table_name> (see Entity::getCacheDir()). Invalidate via:

PostTable::cleanCache();           // DataManager / Table
PostTable::getEntity()->cleanCache(); // Entity — ManagedCache::cleanDir('orm_...')

Writes that change cacheable rows also call cleanCache() from the ORM layer. To clear related TaggedCache HTML, register and invalidate your own tags in event handlers — do not invent ORM_* tag names.

Component Cache

In class.php / component.php:

if ($this->startResultCache(false, [
    $USER->IsAuthorized(),
    $arParams['SECTION_ID'],
]))
{
    $this->arResult['ITEMS'] = $this->fetchItems();
    $this->includeComponentTemplate();
}

Component parameters controlling cache:

  • CACHE_TYPE: A (autocache), Y, N.
  • CACHE_TIME: TTL in seconds.
  • CACHE_GROUPS: Y — key depends on user groups.

Composite Cache

Enable and configure Composite Site in Admin → Settings → Composite Site (or programmatically via Bitrix\Main\Composite\Engine). There is no separate "compression module" requirement for composite.

Consider composite constraints: dynamic blocks are marked via $APPLICATION->SetPageProperty('composite_frame_mode', 'Y') / setFrameMode, personal data should not be in the static part, AJAX components are fetched with a separate request.

Composite zones and NGINX

  • Static zone — full page HTML cache.
  • Dynamic zone (data-dynamic) — refreshed via AJAX on each hit.
  • Autocomposite vs manual composite — configure in Admin → Composite settings.
  • NGINX can serve static composite files directly; configure composite pool path (BitrixVM: Configure nginx to use composite cache).

For ORM/SQL optimization see skill bitrix-performance.

Invalidation by Events

Typical scheme: OnAfterUpdate/OnAfter* handler in the tablet calls $taggedCache->clearByTag(...) for your tags, and/or Table::cleanCache() for ORM query cache. Use new ORM events via EventResult instead of $GLOBALS['USER_FIELD_MANAGER']->....

Antipatterns

  • Caching "live" data (balances, stock levels) with high TTL without invalidation.
  • Using global $_SESSION/$USER inside the cache key instead of explicit variables.
  • One shared cacheDir for all modules — hard to clear selectively.
  • Missing abortDataCache() for empty/error results.
  • Enabling composite without testing dynamic blocks.
  • Assuming TaggedCache tags ORM_<TABLE> exist — use cleanCache() / orm_* ManagedCache dirs instead.

Checklist

  • Cache level selected: short-lived → unmanaged; rarely changing and critical → managed + tags.
  • Cache key includes all parameters affecting the result (filters, language, permissions).
  • Cache invalidation is automated via tags/events, not manual cleanDir('/').
  • ORM query cache cleared via Table::cleanCache() / Entity::cleanCache(), not fictional ORM_* tags.
  • Component cache accounts for user groups where important.
  • Production environment uses Redis/Memcached instead of file cache.

Files included

  • SKILL.md

More skills