NetcaneTechnologies

Strapi

Strapi + Next.js: The Clean Integration Blueprint (REST + Types)

A repeatable way to connect Next.js to Strapi via REST with shared types and minimal coupling.

Yasir Haleem3 min read

Connecting Next.js to Strapi with REST and TypeScript stays maintainable when you centralize the client, share types, and keep fetch logic in one place. This guide gives you a repeatable blueprint: one API client, types that match your content model, and consistent use of populate and query params—so you can build and scale without coupling or type drift.

One API client and base URL

Create a small client that knows the Strapi base URL and adds headers (e.g. Bearer token for draft content). Use env vars for the URL so you can point to different Strapi instances per environment. Centralizing the client avoids scattered fetch calls and makes it easy to add logging or retries later.

// lib/strapi.ts
const STRAPI_URL = process.env.STRAPI_URL ?? "http://localhost:1337";
 
export async function strapiFetch<T>(
  path: string,
  options?: RequestInit
): Promise<T> {
  const url = path.startsWith("http") ? path : `${STRAPI_URL}/api${path}`;
  const res = await fetch(url, {
    ...options,
    headers: {
      Authorization: process.env.STRAPI_TOKEN
        ? `Bearer ${process.env.STRAPI_TOKEN}`
        : "",
      ...options?.headers,
    },
  });
  if (!res.ok) throw new Error(`Strapi ${res.status}: ${path}`);
  return res.json();
}

Use this for all Strapi API calls so base URL and auth live in one spot.

Types that match your content types

Define TypeScript types for each Strapi content type (single types and collection types). Model the response shape: data for single or array, id, attributes, and relations as nested objects or arrays. You can generate these from Strapi’s schema or write them by hand and keep them in sync when you change the admin.

// types/strapi.ts
export interface StrapiImage {
  id: number;
  url: string;
  alternativeText?: string;
  width?: number;
  height?: number;
}
 
export interface StrapiPost {
  id: number;
  attributes: {
    title: string;
    slug: string;
    excerpt?: string;
    content?: string;
    publishedAt: string | null;
    cover?: { data: StrapiImage | null };
    author?: { data: { id: number; attributes: { name: string } } | null };
  };
}
 
export interface StrapiResponse<T> {
  data: T;
  meta?: { pagination?: { page: number; pageCount: number; total: number } };
}

Use these types in your fetch helpers and in Next.js components so you get autocomplete and catch mismatches early.

Populate and query params

Strapi REST uses populate to include relations and fields to limit attributes. Build query params in a helper or pass them explicitly so you don’t over-fetch. For list pages, add pagination (pagination[page], pagination[pageSize]) and filters (filters[slug][$eq]=hello) so the front end stays in control.

const params = new URLSearchParams({
  "populate[cover]": "*",
  "populate[author]": "name",
  "filters[slug][$eq]": slug,
});
const post = await strapiFetch<StrapiResponse<StrapiPost[]>>(
  `/posts?${params}`
);
const single = Array.isArray(post.data) ? post.data[0] : post.data;
if (!single) return null;
return single;

Normalize the response (single vs array) in one place so the rest of the app always gets a consistent shape.

Summary

Use a single Strapi client with base URL and auth, define types that mirror your content types, and use populate and query params consistently. Normalize single vs array responses in one place so the rest of the app gets a consistent shape. That blueprint keeps your Strapi + Next.js integration clean and type-safe from first integration to large content models.

About the author

Yasir Haleem is founder and lead engineer at Netcane Technologies. He builds production Next.js sites with headless CMS platforms — Strapi, Contentful, Sanity, and WordPress — with a focus on performance, SEO, and maintainable architecture.

Let's work together

Tell us about your project. We respond within one business day with a clear scope, timeline, and estimate.