This article is work in progress to help Drupal developers finding out, why a page is not cached in many situations. It can help as a checklist.
I'll add further information in the future, possibly.
Typical reasons for pages not being cached in Drupal 8+
The most simple reason might be, that you forgot to enable caching at /admin/config/development/performance
(Web)form on the page
Quite often the reason for pages not being cached is a (Web)form on the page. It might be a good idea to disable it and try without the form to see if that's causing the issues.
If it's the reason, it's often not the (Web)form itself, but things like spam protection on the form. Have a try without the protection to find if that's the root cause, in the next step. And read on.
CAPTCHA module itself doesn't kill cache, but several CAPTCHA submodules do. For example, Captcha Image does kill page cache!
See https://www.drupal.org/project/captcha/issues/3311447 and help to improve things by design!
Tip: Captcha Riddler module does not kill page cache, if only one question is defined, for example.
For other CAPTCHA submodules there may be separate issues telling you about the status. For example, for reCaptcha: https://www.drupal.org/project/recaptcha/issues/3139188
The honeypot module allows to work with caching enabled, but therefor requires having the honeypot time limit set to "0" (zero).
Antibot module does not kill caches, so it's a good alternative to work with page caching.
As the very first step you should check your Drupal Status report () if it tells you about any issues
Check caching in browser
Use developer tools (F12) and open the "Network" tab.
Click on the first call or any subsequent call to see the response headers.
Drupal core helpers and settings
services.yml now allows to set
renderer.config.debug: true to output cache information in the render output similar to twig debug. For details see the change record: https://www.drupal.org/node/3162480
Drupal cache debugging modules
WebProfiler is the multitool to debug many many properties of the current page. It's based on the symfony
Cache review is quite similar to Renderviz. But I didn't try it yet.
Production check provides a lot of checks to ensure the page is production ready. It's not made for debugging cache, but can help to ensure there are no other issues for production.
Use curl to test caching headers
Simply use the famous curl tool available for Windows and Linux:
curl -I https://www.example.com
And look for:
Cache-Control: max-age=86400, public(should be high (enough)!)
X-Cache-Status: HIT(should be HIT, not MISS!)
Expires:(should be far futures, not past!)
Free Online tools
There are several free tools to check, if your page is being cached, for example: