Magento 2 comes stock with a full page caching feature. However, it's not clear how the framework determines which URL end-points need to be cached. For example, if I create a simple controller that acts as a JSON endpoint

$data = ...;
$result = $this->resultJsonFactory->create();       
return $result->setData($data);

The system seems smart enough to know not to cache this.

curl -I 'http://magento2.example.com/my/custom/endpoint'
X-Magento-Cache-Debug: MISS

I've been able to track the built in caching functionality to this method (used by the built-in plugin)

#File: lib/internal/Magento/Framework/App/PageCache/Kernel.php
public function process(\Magento\Framework\App\Response\Http $response)
    if (preg_match('/public.*s-maxage=(\d+)/', $response->getHeader('Cache-Control')->getFieldValue(), $matches)) {
        $maxAge = $matches[1];
        if ($response->getHttpResponseCode() == 200 && ($this->request->isGet() || $this->request->isHead())) {
            $tagsHeader = $response->getHeader('X-Magento-Tags');
            $tags = $tagsHeader ? explode(',', $tagsHeader->getFieldValue()) : [];

            if (!headers_sent()) {
            $this->cache->save(serialize($response), $this->identifier->getValue(), $tags, $maxAge);

Which seems to examine the response object, and only cache requests if they're a HTTP 200, either a GET or HEAD request. It also uses the Max-Age Cache-Control header to ensure values are saved in the cache for an appropriate amount of time.

So, it's clear from this code that something instructs the system (i.e. sets cache headers on the response) to cache the request. What's not clear is where this happens during Magento's request flow, and which requests gets full page caching and which do not.

  • For me, X-Magento-Cache-Debug is always MISS. Any idea what it could be?
    – MagePsycho
    Commented Oct 9, 2017 at 13:23
  • So how can I cache my Json response? Is this not possible? Commented Feb 18, 2022 at 5:44

1 Answer 1


Response is marked as cacheable in \Magento\PageCache\Model\Layout\LayoutPlugin::afterGenerateXml only in case if there are no blocks in the layout of current page marked with cacheable="false" attribute, like this:

<block class="Magento\Checkout\Block\Registration" name="checkout.registration" template="registration.phtml" cacheable="false"/>

By default all CMS, product and category pages should be cacheable, their layouts were refactored so as not to contain non-cacheable blocks.

Also keep in mind, there is a bug related to usage of cacheable="false" on product pages described here.

  • 2
    Thanks! More on some other important full page cache points here. magento-quickies.alanstorm.com/post/134802803800/… Commented Dec 8, 2015 at 18:29
  • But what about when if i need in custom product extended block ? because if i am put cacheable="false" in xml then it will give error in varnish varnish failed on marketplace submission
    – Himanshu
    Commented Dec 22, 2018 at 11:14
  • 1
    I read your article @AlanStorm. So what is the solution to cache my Json responses? Commented Feb 18, 2022 at 5:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.