I'm using the JSS Headless Proxy which calls down to the Layout Service for SSR. I'm seeing high TTFB to the Layout Service direct:

  • New session: ~400ms to ~500ms
  • Subsequent requests: ~200ms to ~300ms

And therefore high TTFB to the rendered page (includes a 100ms graphQL request):

  • New session: ~600ms to ~700ms
  • Subsequent requests: ~400ms to ~500ms

So layout service is taking a large portion of the time, and then converting the json layout to HTML on the proxy side is also pretty signficant.

There is a decent amount of personalisation in use on various components and tracking is very important, so the caching options described in the documentation here are not able to be used.

Is there any guidance / places to start digging on how to optimise this site?

3 Answers 3


Few ideas for troubleshooting. They are not really related to JSS, but still worth trying:

  1. Where are the servers located? When providing TTFB values are these from a region nearby? E.g. you are measuring from UK client to UK server? Or does it come to e.g. USA? We've been building multi-region delivery for global clients to save time on latency.
  2. Is it really JSS issue? I had a few issues in the past when the issue was related to xDB tracking slowing all responses. Maybe try disabling XP mode and testing the same page in XM mode just to remove any xDB pipelines and processing. It's not always possible within the solution, but still worth trying.
  3. Try investigating JSS response. We had a few components that looked very simple like banners with an Author field. Though when serializing it was loading a huge amount of dependencies through list and link fields. So simple banner that required only Author name was loading whole information about Author, all fields related to Author and then recursively it went down a few levels more. It was bloating JSS response to some crazy MBs for super simple components. We ended up with creating some custom field resolvers for such scenarios.
  4. Subsequent requests in your example take much less time than new session. Can it be related to the cold start of the application? It might be worth having some warm-up script to have these cached.
  5. Final idea - profiling ;) The performance issues are always a pain.

With layout service optimisation the first suggestion would be caching the rendering outputs. If the out of the box caching options don't work for you due to personalisation consider creating custom vary by option that works with personalisation. Here is an example of custom cache vary by option. This was for Sitecore MVC but should work for JSS too.


The other performance considerations depends on your code. You could try reviewing and optimising any custom code you have that could be a performance bottle neck.

Also, in one of the project I worked on we moved all the global component data sources like headers and navigation into a special route and loaded them once instead of loading them on every page load. I am not a front-end developer, so can't help you more on how exactly to implement that.

  • OOTB caching helps a little bit, but it's not a big enough improvement - I am already caching the Navigation and Footer renderings which sitecore debug mode says hits the most items. All of the other components on the page are Promos and dont get a significant amount of items. Commented Apr 19, 2022 at 0:59

Since you're using personalisation it might be a good idea to check if you have custom rules. For example I had the following rule:

public class ProjectStatusCondition<T> : StringOperatorCondition<T> where T : RuleContext

This rule needed to fetch some data from a 3rd party api and always runs when getting data from the Layout Service. So we added some caching to that and it improved the TTFB significantly.

You might also have a custom content resolver (IRenderingContentsResolver) for a specific component which can be slow. If that is the case you could try to move custom logic in there to a separate Web API call. If you're using React you could try the Hybrid Placeholder. With the Hybrid Placeholder it's possible to load heavy parts of a Rendering Contents Resolver later. When a user navigates to a page directly everything will be loaded (with SSR support). When a user navigates to a page using Client-Side Rendering with XHR (single page app) the data is fetched with the Layout Service. Than the heavy parts can be skipped and will be loaded once the page is already visible.

  • Thanks for the reply, but I don't have any custom rules or custom content resolvers. And I need the performance to be good on first load for Google Lighthouse metrics. Commented Apr 19, 2022 at 0:57

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.