Fix LCP Issues on Directus (Loading Speed) | OpsBlu Docs

Fix LCP Issues on Directus (Loading Speed)

Improve Directus LCP by tuning REST/GraphQL response times, using built-in image transforms, and server-rendering your frontend layer.

Largest Contentful Paint (LCP) measures how quickly the main content of your Directus-powered site loads. Since Directus is headless, LCP optimization focuses on both backend API performance and frontend rendering efficiency.

Target: LCP under 2.5 seconds Good: Under 2.5s | Needs Improvement: 2.5-4.0s | Poor: Over 4.0s

For general LCP concepts, see the global LCP guide.

Directus-Specific LCP Issues

1. Slow API Response Time (TTFB)

The most critical factor is how quickly your Directus API responds.

Diagnosis:

  • Open Chrome DevTools → Network tab
  • Look for requests to your Directus API
  • Check "Waiting (TTFB)" time
  • Target: TTFB under 200ms

Solutions:

A. Enable Directus Caching

# .env in Directus
CACHE_ENABLED=true
CACHE_STORE=redis
CACHE_REDIS=redis://localhost:6379
CACHE_TTL=30m

B. Optimize Directus Queries

// Bad - fetches everything
const articles = await directus.request(
  readItems('articles', {
    fields: ['*', '*.*.*'],
  })
);

// Good - only fetch needed fields
const articles = await directus.request(
  readItems('articles', {
    fields: ['id', 'title', 'slug', 'featured_image.id'],
    limit: 10,
  })
);

C. Use GraphQL for Precise Data Fetching

// Fetch exactly what you need in one request
const { data } = await fetch(`${DIRECTUS_URL}/graphql`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: `
      query GetArticle($slug: String!) {
        articles(filter: { slug: { _eq: $slug } }) {
          id
          title
          content
          featured_image {
            id
            filename_disk
          }
        }
      }
    `,
    variables: { slug },
  }),
});

2. Unoptimized Images from Directus

Solutions:

A. Use Directus Image Transformations

// Next.js Image component with Directus
import Image from 'next/image';

const directusImageLoader = ({ src, width, quality }) => {
  return `${process.env.NEXT_PUBLIC_DIRECTUS_URL}/assets/${src}?width=${width}&quality=${quality || 75}&format=webp`;
};

<Image
  loader={directusImageLoader}
  src={article.featured_image.id}
  alt={article.title}
  width={1200}
  height={600}
  priority={true}  // For LCP images
/>

B. Preload LCP Image

// app/articles/[slug]/page.tsx
export default function ArticlePage({ article }) {
  return (
    <>
      <link
        rel="preload"
        as="image"
        href={`${process.env.NEXT_PUBLIC_DIRECTUS_URL}/assets/${article.featured_image.id}?width=1200&format=webp`}
      />
      <article>{/* Content */}</article>
    </>
  );
}

3. Framework Rendering Strategy

Next.js SSG (Best for LCP):

export async function generateStaticParams() {
  const articles = await directus.request(readItems('articles', { fields: ['slug'] }));
  return articles.map(article => ({ slug: article.slug }));
}

export default async function ArticlePage({ params }: { params: { slug: string } }) {
  const article = await directus.request(
    readItems('articles', {
      filter: { slug: { _eq: params.slug } },
    })
  );
  return <ArticleContent article={article[0]} />;
}

Quick Wins Checklist

  • Enable Directus cache (Redis)
  • Optimize Directus API queries (limit fields)
  • Use Directus image transformations
  • Implement SSG/ISR instead of SSR
  • Preload LCP images
  • Use GraphQL for precise data fetching
  • Enable CDN for Directus assets
  • Implement code splitting
  • Use font-display: swap

Next Steps

For general LCP optimization strategies, see LCP Optimization Guide.