Frontend Setup

The Next.js frontend consumes Directus via GraphQL. Get it running locally in under 5 minutes.

Prerequisites

  • Node.js 20+ (npm is fine: the frontend uses plain npm, no pnpm).
  • A running Directus instance. See Directus CMS Setup for the zero-command path.

Install

cd frontend
npm install

Environment variables

Create frontend/.env.local:

NEXT_PUBLIC_DIRECTUS_URL=http://localhost:8055
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_DEFAULT_LOCALE=en

No token required. The Directus Public role has read access on every content collection, granted automatically by the bootstrap script. Build-time and runtime fetches are unauthenticated GraphQL queries.

Optional variables:

VarPurpose
RESEND_API_KEYEnables the contact-form email delivery path.
NEXT_PUBLIC_GA_IDGoogle Analytics
NEXT_PUBLIC_GTM_IDGoogle Tag Manager
NEXT_PUBLIC_BOOKING_URLCalendly / Cal.com link shown in the floating booking CTA.

Run

npm run dev

Open http://localhost:3000. Default locale is English at / (also accessible at /en). Other locales live at /fr and /es.

How the GraphQL client works

The frontend talks to Directus via POST /graphql: no REST, no SDK, just typed fetch() calls against the schema Directus exposes.

All fetchers live in frontend/src/lib/directus.ts:

// Example: services with EN translations
export async function getServices(locale: string): Promise<Service[]> {
  const data = await gql<{ services: Service[] }>(
    `query ($locale: String!) {
      services(sort: ["sort"]) {
        id slug icon sort seo
        translations(filter: { languages_code: { code: { _eq: $locale } } }) {
          languages_code { code }
          title description features
        }
      }
    }`,
    { locale }
  );
  return flattenList(data?.services);
}

Responses are flattened so the rest of the app sees languages_code: "en" instead of the GraphQL-shaped { code: "en" }.

Next.js fetch caching is on by default with a 60-second revalidation: CMS edits appear without a rebuild.

Type-check and build

npm run lint
npm run build

Both must pass with zero errors before deploying.

Next steps