Why a Strapi Next.js integration is harder than the first API call
The first API call to Strapi takes minutes, but the integration takes longer because it is a set of decisions about API style, public access, preview, caching and revalidation. Most of the effort sits in those decisions, and comparatively little sits in the first fetch. A team usually reaches this point when a second front end appears, such as a Next.js marketing site alongside a Nuxt portal or a mobile app, when editors need to see unpublished changes before they go live, when publishing becomes frequent, or when traffic makes the content path a performance concern. Any one of these pushes the project beyond a tutorial, and each front end needs the same content in a shape it can use.
The first difficulty is draft and published states. Strapi 5 keeps draft and published versions of entries, so a front end that reads the wrong state either shows unfinished work or hides approved changes. The second is response shape. Strapi 5 changed the API response format from v4, so examples written for earlier versions may return different fields, and the Strapi-Response-Format: v4 header is a migration aid rather than a long-term design. The third is relations and population. Related entries, components and media are not returned unless the query asks for them, and asking for too much produces large payloads. Ask the team to measure response size for each page template before the design is fixed.
Caching and cross-origin access cause the most surprises after launch. Pages that are statically generated or cached by a fetch layer keep old content until they are rebuilt or revalidated, so an editor can publish a change and see nothing happen. Revalidation needs a trigger, usually a Strapi webhook that calls the front end with a shared secret, plus a plan for failed deliveries. CORS is the other common gap. Browser-side calls from client components or a mobile web view need their origins allowed in Strapi, and a list that works in development can fail in production. Confirm the allowed origins for each environment and test them from a real browser session.
The API style is the decision that lasts longest. Strapi 5 supports REST and GraphQL on all self-hosted plans, according to the Strapi self-hosted pricing page, so the choice is about fit rather than licensing. It shapes query helpers, typed clients, cache keys and how preview reads content, and it affects front-end code for years. Settle these questions before components are written: which state preview reads, which public role or API token each front end uses, where webhooks run and who owns the revalidation secret. Ask any implementation partner for a written list of these decisions as part of the scope, with each one assigned to a named owner.
Which Strapi parts the front end depends on
A Next.js, Nuxt, Astro or mobile front end reads Strapi through a short chain of settings: schema, API surface, access rules, tokens, publishing state, events and browser permissions. Each part below controls one link in that chain, and a mistake in any one of them usually shows up as an empty page, a stale page or a blocked request rather than a clear error.
Content types, components and dynamic zones
Content types define the collections your front end queries, components define reusable blocks inside them, and dynamic zones let an editor place a mix of components in a fixed order. The front end must request these structures explicitly, usually with populate parameters, because nested components and zones are not returned by default. If a component is renamed or moved in the schema, the query that worked yesterday can return empty fields today. Check every field your templates render against the current schema before each release.
Relations and populate depth
Relations link entries such as an article to its author or category, and the API returns them only when the query asks for them. Deep population improves convenience but increases response size and database work, which is why many front ends request only the fields a page needs. When a relation is missing from a response, the usual causes are an unpopulated field or a related entry the public role cannot read. Confirm which relations each page template uses and set population limits in the query layer, not in ad hoc requests.
REST and GraphQL API surface
Both APIs expose the same content, but they differ in how queries are shaped, cached and permissioned. REST is simpler to cache at the CDN level because each URL maps to a resource, while GraphQL sends queries in request bodies that many proxies and CDNs do not cache by default. Pick one API per front end where possible, and confirm that the GraphQL plugin or endpoint is enabled in your Strapi build before designing queries around it. Changing the choice later usually means rewriting every data-fetching function.
Users and Permissions public role
The Users and Permissions plugin defines what unauthenticated visitors can read through the public role. This is the setting that most often causes a public site to return empty data after launch, because each content type and action must be enabled for the public role separately. It is also the setting most likely to expose more than intended if it is opened broadly to make a test pass. Review the public role for each content type the front end reads, and record which fields and actions it allows so the review can be repeated after schema changes.
API tokens for server-side reads
API tokens authenticate server-side calls from Next.js route handlers, server components, build jobs or an Astro server, so that drafts and restricted content can be read without exposing credentials in the browser. Each token has a type and scope, and a read-only token is the appropriate choice for most rendering work. Store the token in the front end's server environment only, and rotate it through your secrets process. A token that is missing or scoped too narrowly typically produces 401 or 403 responses during build or preview, not in the public page.
Draft and published states
Strapi keeps draft and published versions of an entry, and the public API returns only published content unless a request asks for drafts with an authorized token. Preview features depend on this split, so a page can show correct draft content in preview and still be empty on the live site if an entry was never published. Confirm how your Strapi version exposes draft status in the API before building preview routes, and test a preview link with a real unpublished entry as part of acceptance testing.
Webhooks for cache revalidation
Webhooks notify the front end when entries are published, updated or unpublished so that cached pages can be rebuilt or revalidated. Without them, the site shows old content until a cache expires or a deployment runs, which editors often report as the CMS not working. The webhook endpoint must be reachable from Strapi, must verify the request source, and should be tested with each event type the site relies on. Confirm the exact events your Strapi version emits and your framework's revalidation method before writing the handler.
CORS for browser requests
CORS settings control which browser origins can call the Strapi API directly. A client-side fetch from a Nuxt single-page app, a mobile web view or a separate admin tool fails silently if the origin is not allowed, while server-side rendering in Next.js is unaffected. Allow only the exact production and preview origins, avoid wildcards on endpoints that serve authenticated data, and test from a browser on each origin. Server-rendered routes can hide a CORS gap until someone builds a client-side feature that calls the API directly.
REST or GraphQL for Next.js and mobile front ends
This table compares REST, GraphQL and a hybrid for Strapi front ends, and where the API call runs: on the Next.js server or in the browser. Read each row against your team skills, number of front ends, caching needs and mobile payload size. The main takeaway is that the call location decides where API tokens live and what can be cached, so settle that before choosing the query style.
| Option | When it fits | Operational cost |
|---|---|---|
| REST with fixed populated endpoints | Few front ends, a team that knows HTTP, pages that map to known content shapes | Cache keys follow the URL and query string. Populate settings must stay in step with each page. |
| GraphQL with client-defined queries | Several front ends with different data needs, or mobile clients where payload size matters | Ad hoc queries work poorly with standard HTTP caching. Set depth and complexity limits and test them with each client. |
| Hybrid: REST for pages, GraphQL for mobile | Web pages need stable, cacheable responses while mobile screens need flexible field selection | Two contracts to version and test. A shared schema review and shared types reduce drift between them. |
| Calls from Next.js route handlers or server components | Web front ends where the API token must stay private and pages are cached or revalidated | The token stays on the server. Needs revalidation after publish and a plan for cache invalidation. |
| Calls from the browser | Public, read-only content served to anonymous or end-user access | Anything in browser code is visible. Relies on Users and Permissions scope, CORS and rate limits, and cannot use a server cache. |
| Response format after a Strapi 5 upgrade | Teams moving clients from v4 or running both versions during migration | Strapi 5 changes the response format. The Strapi-Response-Format v4 header supports backward compatibility, so confirm how long clients need it. |
| Debugging and observability | Teams with limited GraphQL experience or heavy use of nested populate | REST failures trace easily by URL. GraphQL needs operation names and query logging to trace failures to a client. |
How to wire a Next.js front end to Strapi, step by step
This sequence takes a Strapi project and a Next.js front end from first install to a published change appearing on a rendered page. Each step ends with a concrete check, so the team knows the connection is secure and correct before adding more page types.
Confirm runtime and database requirements
Before installing anything, confirm which Strapi 5 minor version the project will run and check its supported Node.js and database versions in the installation documentation. Strapi 5 runs only on Active or Maintenance LTS Node.js versions and supports PostgreSQL 14 or later, MySQL 8.0 or later, MariaDB 10.3 or later and SQLite 3, but not MongoDB or other NoSQL databases. Your team should check the current Strapi installation requirements for the exact version, because minor releases ship frequently. The check passes when a fresh install starts on the target Node.js LTS against the chosen database and the admin panel loads.
Model content around front end queries
Design content types and components around the page layouts the front end will render, not around the database tables. Keep relations explicit, decide which fields are required for each page, and avoid deep nesting that forces the front end to request everything with a single broad populate. Write down the query each page type needs, including fields, relations and sort order, and review that list with the front end developers. The check is a set of sample REST requests that return only the fields each page uses, with no unused relations included in the default response.
Lock the public role to published read access
In the Users and Permissions settings, set the Public role to read only, and enable find and findOne only for the content types the website displays. Confirm that draft content is not returned to anonymous requests, because the public API must serve published entries only. Review any custom routes or plugins for write access that was enabled by default. The check is an unauthenticated request for a draft entry that returns not found, alongside a request for a published entry that succeeds, and an attempted create or update that is rejected.
Create a scoped read token outside the client bundle
Create a read-only API token in the admin panel, limited to the content types the front end needs, and set its lifetime according to your rotation policy. Store the value in server-side environment variables for the Next.js application, such as the server runtime configuration, and never prefix it with a variable name that the browser bundle can read. Document who can rotate the token and where the value lives in each environment. The check is a build of the production bundle that fails when the variable is removed, and a search of the client output that finds no token value.
Write a typed data-access layer
Create one module in the Next.js project that wraps every Strapi request. It should build populate and filter parameters from typed query objects, apply pagination with explicit page size limits, normalize the response into the shape your components expect, and throw clear errors on non-success responses. Keep this layer as the only place that knows the Strapi response format, so a future API change affects one file. Include the Strapi response format setting your version uses in the tests. The check is a unit test suite that covers filters, a paginated list, a missing entry and a malformed response.
Render one page type end to end
Pick a single page type with a list and a detail view, such as articles, and build both routes using the data-access layer. Decide whether each route is statically generated, server rendered or incrementally regenerated, and document the revalidation interval or trigger. Handle empty states and missing entries without exposing internal error details. The check is a production build that generates the list and detail pages and a manual review of the rendered HTML showing the expected fields and no admin or token data.
Confirm a published change reaches the page
Edit an entry in the admin panel, save it as a draft, and confirm the public page does not change. Publish the entry, then wait for the revalidation window or trigger the revalidation path you configured, and confirm the new content appears on the rendered page. Repeat with an unpublish action to confirm the page stops showing the entry. The check is a recorded sequence of draft, publish and unpublish results, each matched against what the public route returns. Any mismatch points to a permission, populate or caching setting to fix before adding more page types.
How to preview Strapi drafts in Next.js without leaking them
Editors need to see unpublished Strapi content rendered in the same Next.js layout the public will see, while anonymous visitors must never receive a draft. The section's point is that preview is a separate access path with its own secret, its own credentials and its own lifetime, and it has to be designed that way from the start. If the preview route, the draft fetch and the public fetch share the same cache key, the same token or the same unguarded route, drafts can reach the public site even when every editor behaves correctly.
The approach that holds up is a preview route in the Next.js front end that first validates a secret supplied by the CMS or the editor's link. Only after that check passes does the route fetch draft content from Strapi, using a read credential that lives on the server and is never placed in client-side code, a query string or a cookie the browser can read. Once the content is confirmed, the route sets Next.js preview mode with a short lifetime, and a separate exit route clears that state. Confirm the exact preview configuration in Strapi and the preview mode API for your pinned Strapi and Next.js versions, because both have changed across releases and the setup differs by version. Check the official documentation for those versions rather than copying older examples.
The failure modes are predictable, so plan checks for each one. The first is draft content cached by a shared CDN: a preview response, or a public page rendered with draft data, can be stored at the edge and served to everyone. Verify that preview responses send no-store style headers, that preview requests bypass the CDN or use a distinct path, and that a request without the preview cookie never returns draft fields. The second is preview links that work indefinitely: a leaked URL should stop working after a bounded period or after the editor exits. Test expiry and exit explicitly. The third is an editor previewing a draft that is then unpublished or rejected, which leaves a stale view in a browser tab or cache. Agree with the editorial team how long previews may be trusted and how unpublishing is communicated.
Before launch, run a short verification set. Request the public site and confirm no draft-only fields appear. Request the preview route without the secret and confirm it is refused. Request it with a valid secret, confirm drafts render, then exit and confirm the cookie is cleared and drafts disappear. Repeat the test after the preview cookie expires, and from a different network path to confirm the CDN is not caching preview output. Record which Strapi roles and API tokens can read drafts, since a token with broader scope than the preview route needs widens the exposure. Ask the implementation partner to document the secret rotation steps and the owner who performs them.
How the integration changes across Next.js, Nuxt, Astro and mobile
Next.js is the most sensitive family to where fetching happens. Server components, route handlers and server actions run on the server and can hold the Strapi token, while anything shipped to the browser cannot. The main decisions are which routes are statically generated, which are rendered per request, and how a publish in Strapi reaches pages that already exist.
- Default caching: Confirm how your pinned Next.js version caches fetch calls and route output, because caching defaults have changed between releases. Set cache and revalidation options explicitly on every Strapi request.
- Token location: Keep the Strapi API token in server components, route handlers or server actions only. Public content can use the Public role without a token, and private content should never reach client bundles.
- Preview: Use a route handler that checks a preview secret, enables draft mode and requests draft status from Strapi. Limit draft mode to authenticated editors.
- Change propagation: Trigger on-demand revalidation from a Strapi webhook on publish, tagging or pathing each content type. Time-based revalidation works as the fallback.
- Webhook reliability: Test retries and duplicate deliveries, since a missed webhook leaves stale pages until the next revalidation window.
Before committing, list which pages must reflect a publish within seconds and which can wait for a scheduled rebuild, then confirm both paths with your team's Next.js version.
Nuxt splits work between the client, the rendering layer and server routes under the server directory. Server routes are the natural place for the Strapi token, and hybrid rendering rules let each route choose prerendering, cached server rendering or per-request rendering. The integration decisions are mostly about which rules apply to which Strapi content types and how cache entries expire after an edit.
- Default caching: Confirm which route rules your project sets, since prerendered, cached and uncached routes behave differently when content changes. Do not assume a route is fresh because the framework version is current.
- Token location: Store the Strapi token in private runtime configuration and call Strapi only from server routes or server utilities. Expose only the public base URL to the client.
- Preview: Add a server route that sets a preview cookie after checking a secret, then requests draft content from Strapi for that session. Keep the cookie scoped and short-lived.
- Change propagation: For prerendered routes, a Strapi webhook can trigger a rebuild or a cache purge. For cached server routes, invalidate the matching entries or let them expire on a defined interval.
- Upgrade effects: Check how Nuxt version changes affect route rules and server utilities before upgrading, and retest preview after each change.
Before committing, map each Strapi content type to one rendering mode and one invalidation method, and confirm the mapping with editors who publish time-sensitive content.
Astro defaults to static output, with JavaScript limited to interactive islands. That makes the Strapi token a build-time concern for most pages, and it makes publish timing a deployment question. Server endpoints or an SSR adapter are needed only for routes that must read Strapi on each request, such as preview or private content.
- Default caching: Static pages are fixed until the next build, so caching is set by your hosting platform and any deploy process. Confirm what the host caches at the edge for SSR routes.
- Token location: During builds, the token lives in the build environment only. For SSR endpoints, keep it in server-side environment configuration. Islands should receive public data as serialized props, never the token.
- Preview: Preview normally needs an SSR route or a separate preview deployment that requests draft content. Protect that route with a secret and avoid publishing preview output to the production site.
- Change propagation: Connect a Strapi webhook to a deploy hook that starts a rebuild on publish. For large sites, confirm the build time is acceptable for the content editors' expectations.
- Island data flow: Fetch content in page frontmatter where possible, and pass only the fields each island needs to keep payloads small.
Before committing, decide which pages must be static, which need SSR, and how long a rebuild can take before editors need a faster route for urgent changes.
Native and cross-platform mobile apps change the integration more than any web framework does. The app binary is distributed to devices and can be inspected, so it must never contain the Strapi admin or full-access token. Content also reaches users through app releases, device caches and network conditions that a web server does not face.
- Token location: Use public read access for public content, or authenticated user sessions for private content. If the app needs privileged operations, route them through your own backend that holds the credentials.
- Offline caching: Store fetched content on the device with a version or update timestamp. Define what is kept offline, how long it lasts and how conflicts with draft edits are avoided.
- Payload size: Request only the fields and relations each screen uses, and size images through your media delivery setup. Mobile networks make oversized responses visible to users.
- Release cycles: App store review adds delay, so API and content model changes must support older app versions still in use. Plan field removals across at least one release cycle.
- Push-based refresh: Send a notification or silent push after a publish, and have the app pull changed entries. Keep a pull on launch as the fallback when push is delayed or disabled.
Before committing, confirm which content must work offline, which app versions your API must support, and how a change published at 9 a.m. reaches users who have not opened the app.
How webhooks and revalidation keep Strapi content fresh
Stale content in a Strapi and Next.js build usually comes from one of three layers, and each needs its own invalidation plan. The first is the framework's data cache, which stores the results of fetch calls to the Strapi REST or GraphQL API. The second is the CDN or edge cache in front of the front end, which may hold rendered pages or API responses for other visitors. The third is the browser cache, which controls how long a visitor's own client keeps a page or asset. A publish that clears only one of these layers will still show old content somewhere. Before building anything, ask the front-end team to list which of the three layers each route passes through, and which headers or settings control each one.
Strapi can send webhooks when entries are published, updated or unpublished. A webhook receiver in the front-end application, or a small service beside it, can use the event payload to revalidate only the affected paths or cache tags, rather than rebuilding the whole site. The mapping between content type and path is a design decision that belongs to the project: for example, a change to a shared navigation entry may affect every page, while a change to one article affects its detail page and a listing. Confirm the event names, the payload fields and how the content type and entry identifiers appear in each Strapi version you run against the Strapi webhook documentation, and do not rely on field names from older examples. The receiver must reject requests that do not carry the shared secret you configured, and it should compare secrets in constant time. It must also be idempotent. Strapi, the network or a retry policy can deliver the same event more than once, and revalidating the same path twice should be harmless. Log the event identifier or a combination of event name, entry identifier and timestamp so that duplicate and out-of-order deliveries can be seen during testing.
Webhooks are not guaranteed to arrive, so plan fallbacks before launch. Common options are periodic revalidation, where the front end refreshes a set of pages on a fixed schedule; a manual rebuild or revalidation control that an editor or operator can run when content looks wrong; and a monitoring check that requests a short list of known pages and compares their content with the expected source. The right mix depends on how quickly editors need changes to appear and how much traffic reaches the site. Each fallback adds cost in build minutes, API requests or monitoring, so ask for those costs to be written into the scope. Cache lifetime should be decided per content type, not set once for the whole site. Pages that change rarely, such as policy text, can carry long lifetimes with explicit invalidation. Content that editors update often, such as news or product availability, may need short lifetimes or no shared caching at all. Record the decision in a table that lists each content type, the paths it appears on, the cache layers involved, the revalidation trigger and the maximum acceptable staleness. Review that table with the business owner, because the acceptable delay is a business decision, not a technical default.
Testing needs real events. Create a staging environment that uses the same front-end caching configuration as production, then publish, update and unpublish sample entries in each content type and confirm that the expected paths refresh in the CDN and in a fresh browser session. Test a delivery with a wrong secret, a repeated delivery and a delivery that arrives after a later update. Then disable the webhook for a short window and confirm that the fallback check or scheduled revalidation catches the change. Record the results, because they become the runbook for operators and the baseline for later upgrades of Strapi or the front-end framework. For the team deciding between building this internally and engaging a partner, the work splits into design (content-to-path mapping, cache table, fallback choices), build (receiver, secret handling, revalidation logic, monitoring) and verification (staging tests and the runbook). Ongoing costs include monitoring, periodic reviews when content types change, and retesting after framework or Strapi upgrades. Ask any partner to state which of these items are in the fixed scope and which are retainer work.
What drives the effort and cost of a Strapi front-end integration
This table compares the factors that move effort and cost for a Strapi front-end integration, with a column for how each driver grows and a column for how to keep it down. Read it before scoping, because the drivers you control at design time usually matter more than the hours spent on build. Most overruns come from preview, cache freshness and environment decisions made late, not from the number of page templates alone.
| Driver | Why it changes effort or cost | How to keep it down |
|---|---|---|
| Number of front ends and platforms | Each web, mobile or second framework needs its own fetching layer, auth handling, preview wiring and test suite, so effort multiplies rather than adds. | Put one shared data layer or typed API client in front of Strapi and reuse it across Next.js, Nuxt, Astro or apps. |
| Page templates and content types | Every template maps to queries, components and cache rules, and every content type adds fields that must render correctly in each template. | Agree the template inventory early, reuse components across templates, and remove unused content types before build starts. |
| Relations and dynamic zones | Deep relations and dynamic zones need nested population, which increases query complexity, response size and the number of rendering branches to test. | Limit populate depth to what each template renders, select only needed fields, and document which components can appear in each zone. |
| Editorial preview requirements | Draft preview for editors needs a separate route, draft-aware fetching, authentication and a way to show unpublished versions, which is usually one of the larger one-time items. | Decide early which content types need preview, use one preview route pattern, and test it with real editor roles before scope is fixed. |
| Cache freshness requirements | Near-instant updates after publish need on-demand revalidation or webhooks tied to cache tags, while looser freshness allows simple time-based caching with less build and fewer failure paths. | Set freshness per content type, use clear cache tags tied to content IDs, and test publish-to-visible timing in staging. |
| Traffic and CDN architecture | Public traffic patterns, edge caching, image delivery and rate limits change how the API is called, what gets cached and how load is tested before launch. | Serve most public reads from the front-end cache or CDN, keep the Strapi API calls at build or revalidation time, and confirm load targets with the team that owns hosting. |
| Internationalization | Each locale multiplies content variants, fallbacks, routing rules and preview paths, and changes how translations are reviewed and published. | Confirm the locale list and fallback rules at design time, and limit the number of locales that need full preview. |
| Environments and access controls | Dev, staging and production need matching schemas, API tokens scoped per environment, and separate editor roles, so differences between environments create most late defects. | Keep a staging copy that matches production in schema and plugins, scope API tokens per front end and environment, and manage role changes through reviewed configuration. |
| Compliance evidence | Audit trails, role reviews, change records and test evidence add documentation and review work, and the exact requirements depend on the assessor and framework. | Ask the assessor or internal compliance lead which evidence they expect before design, and collect it from the start rather than at the end. |
How to keep the front-end path to Strapi private and read-only
A Next.js, Nuxt, Astro or mobile front end should only ever read the content it renders, and only through credentials that cannot change anything. The cards below cover the public role, server-side read tokens, preview access, webhooks, origin rules and the points where user input would write back into Strapi.
Public role limited to rendered fields
The Public role is what anonymous visitors and unauthenticated front-end requests receive. Grant find and findOne only on content types the site renders, and untick individual fields that are internal, such as draft notes, reviewer names or pricing rules. Check the role against real responses from the front end, because a field that is never displayed can still be exposed through a direct API call. Keep create, update and delete unchecked for Public.
Separate read-only tokens for server fetching
Server-side rendering code should use a read-only API token scoped to the content types it needs, not a full-access token or an admin account. Create one token per front-end application or environment so that a leak can be revoked without breaking the others. Record an owner and a rotation schedule for each token, and confirm during implementation how the Strapi version in use handles token rotation without downtime.
Keeping tokens out of client code
Any variable prefixed for browser exposure, such as NEXT_PUBLIC_ in Next.js or PUBLIC_ in Astro, is written into the JavaScript bundle that every visitor downloads. Read tokens, preview secrets and webhook secrets must stay in server-only environment variables and be called only from server components, route handlers or build steps. Inspect the built output and the network tab after each release to confirm that no token value appears in client files.
Preview secrets and short-lived preview cookies
Preview mode shows draft content, so it needs its own access path. Use a preview secret that is separate from the read token, validate it in the preview route handler, and set a cookie with a short expiry that is cleared when preview ends. Confirm how the chosen front-end framework stores preview state and whether a stale cookie can keep drafts visible on a public URL after the editor has finished.
Webhook secret verification
Strapi webhooks that trigger rebuilds or cache revalidation are plain HTTP requests, so the receiving endpoint must reject calls it cannot authenticate. Store a shared secret on both sides, verify it on every request before revalidating anything, and return an error for mismatches. Also restrict which events fire the hook, so that a draft save or a failed publish does not start unnecessary builds.
CORS allowlists for real front-end origins
Browser-based requests to Strapi are governed by the CORS settings in the server configuration. List only the production, staging and preview origins that actually call the API, and avoid wildcards on any environment that exposes non-public content. Server-rendered frontends make requests from the server, so they may not need a browser origin at all. Review the list whenever a domain is added, retired or moved to a new host.
User input and forms that write to Strapi
Contact forms, comments and other user-generated content are the main way a public front end can write into the CMS. Avoid granting create permissions to Public. Instead, send submissions to a server route in the front end that validates input, applies rate limits and stores the entry with a dedicated restricted token or a custom endpoint. Decide whether submissions become published content or sit in a review state, and confirm that moderators can reject them before publication.
How to test that Strapi content reaches the front end and fails safely
The test plan for a Strapi connection to Next.js, Nuxt, Astro or a mobile app should have four groups, because each answers a different question. Contract tests ask whether the response shape the front end depends on still exists. Publish-to-visible tests ask whether a change made in the admin panel reaches a rendered page within the freshness window your team agreed with the business. Negative tests ask whether anything that should stay hidden stays hidden. Failure tests ask what visitors see when Strapi is unavailable. Write the plan down before the first build, with one named owner per group, so that a failing test arrives with a clear decision attached to it.
Contract tests should request the exact fields each page component reads: content type names, attribute names, relation populates, pagination metadata and media formats. Run them after every Strapi upgrade and every schema change, including the frequent Strapi 5 minor releases, because a renamed attribute or a changed relation shape can break pages silently at build time or at runtime. If you are on Strapi 5, confirm which response format your fetch layer expects. Strapi 5 changed the API response format from v4, and the Strapi-Response-Format: v4 header exists only as a migration aid. A contract test should state which format it asserts and fail when the other one appears. Keep fixtures small and stored in the repository beside the front-end data code, so the person who changes the schema also sees which pages it affects.
Publish-to-visible tests create or edit a test entry in staging, publish it, and then poll the rendered page or the revalidation path until the change appears or the window expires. Measure the result against the window in your requirements document. Confirm that the Strapi webhook reaches the front end, that the revalidation call succeeds and that the page shows the new text. Negative tests run as an anonymous client with no session. Request draft and unpublished content through every route the front end uses, and confirm that those routes return nothing. Search the built JavaScript bundles and HTML for the API token value and any other secret. Send the webhook endpoint a request with no secret, a wrong secret and a secret from before the last rotation, and confirm that each one is rejected without side effects.
Failure tests stop or block the staging Strapi instance and observe the front end. Confirm which pages still serve from cache, how long stale content remains acceptable to the business, and whether uncached pages show a clear error state with a retry path. Check response bodies and server logs for stack traces, database hostnames, file paths and token fragments. The exact behavior depends on the rendering mode and hosting, so confirm with your front-end engineers which pages are static, which use incremental regeneration and which call Strapi on every request. Record the results in a table that product owners can review, so each degraded state is either accepted or fixed before launch.
Run the groups in CI in this order: contract tests on every pull request that touches the schema, the fetch layer or the front-end data code; negative and failure tests on each merge to the main branch; and publish-to-visible tests on a schedule and before each release. All of them should target a staging Strapi instance on the same Strapi version as production, with the same Node.js LTS line, database engine and plugin set. A pass on a different version proves little about production. Seed staging content from a fixture script, keep the API tokens and webhook secret in the CI secret store, and configure the pipeline to fail closed. Before accepting the plan, ask your partner or internal team to show the pipeline run history and the exact version tags in use.
Can our team build the Strapi Next.js integration in-house?
What drives the cost of a Strapi Next.js integration?
Scope drives cost more than the framework does. The main components are content model design, the data fetching layer in each front end, preview mode for editors, caching and revalidation rules, API roles and permissions, and testing. Most of this is one-time build work, while hosting, Strapi plan fees, and front-end and Strapi updates recur. Costs rise with the number of content types and relations, the number of front ends (Next.js, Nuxt, Astro, mobile), the volume of content to migrate, and the number of editorial workflows. To ask for a quote, request a written scope that lists each content type, each front end, the preview and revalidation behavior, who signs off, and what is excluded. Ask for the build fee and any third-party subscriptions as separate line items, so you can see which costs you pay directly and which recur.
How long does a Strapi Next.js integration take to build?
The duration comes from the written scope, and this page does not give one. The factors that set it are the number of content types and relationships, how many front ends consume the API, whether preview and on-demand revalidation are required, how much content must be migrated, and how quickly decisions and access arrive from your side. Code effort is rarely the bottleneck. Delays usually come from open content model questions, late design sign-off, and waiting for staging credentials or hosting access. A single public site reading a stable content model is a much smaller job than a multi-brand build with editorial preview across several front ends. Ask for milestones with the client dependencies written next to each one, and confirm what is excluded, such as content entry, copywriting, or editor training.
What does our team need to provide before the build starts?
Name one owner for each decision area before work begins: content model sign-off, front-end design and components, preview and editorial workflow, and hosting and access. Provide staging access to a Strapi instance, the front-end repositories, and accounts for the hosting environment where each front end will deploy. Supply design files or component specs, plus the preview requirements: which pages editors must see before publishing and on which domains. Decide the caching freshness target for each page type, meaning how stale content may be, because that choice determines whether you need webhooks, on-demand revalidation, or time-based revalidation. List the content types with their fields and relations, the roles that will edit content, and which fields are public through the API. Open decisions in these areas are a common cause of waiting during a fixed-scope build.
Can an in-house team build a Strapi Next.js integration?
Yes, if the team has front-end experience with Next.js or the framework you choose and working knowledge of the Strapi content API. An in-house team can handle this work when it tests the API contracts between Strapi and each front end and tests the revalidation path from publish to live page. Contract tests catch changed field names, relation shapes, and response formats before editors find them. Revalidation tests confirm that a publish in Strapi reaches the right pages within the freshness target you set. Teams without recent Strapi 5 experience should plan time for the Document Service API and the changed response format, since both differ from earlier versions. Ask whether your engineers have shipped preview mode and webhook-triggered rebuilds before, because those are the parts that tend to fail quietly.
Should we use REST or GraphQL with Strapi?
It depends on your front ends and your team, and the decisions table on this page sets out the trade-offs. REST is often easier to cache at the HTTP layer and to debug with standard tools, and it fits front ends that request fixed page shapes. GraphQL lets each client ask for exactly the fields and relations it needs, which helps mobile apps and clients that compose varied views from many content types. Strapi's self-hosted plans include both REST and GraphQL APIs, so plan choice does not settle this question. Confirm three things before you choose: how many front ends will consume the content, whether they need deep relation queries, and whether your team already operates GraphQL tooling and query cost controls. Whichever style you pick, record it in the API contract and test it with the same rigor.
Who maintains the integration after launch?
Your team or a retained partner must own three recurring changes: Strapi version updates, front-end dependency updates, and content model changes. Strapi ships minor releases often, so assign someone to review each release notes, test it in staging, and schedule the upgrade. Frameworks and libraries also change, and a Next.js upgrade can alter data fetching or caching behavior, so run the contract and revalidation tests on every update. Content model changes need a rule: any new field or relation must reach the front-end types and preview templates before it goes live. Document the owner for each area, the test suite that proves the integration works, and the rollback steps. DeployOpen offers ongoing support, upgrades, and continuous testing as retainers, scoped in writing.
Which Strapi plan do we need for editorial releases and SSO?
The plan you choose affects editorial features more than the API itself. All self-hosted plans include REST and GraphQL APIs with unlimited entries and API calls, according to Strapi's self-hosted pricing page. Content history and releases start at the Growth plan, which the same page lists at 45 US dollars per month including 3 users, plus 15 dollars per extra user. SSO for administrator login is an add-on on Growth and included in Enterprise, and audit logs and review workflows are Enterprise features. Administrator SSO is separate from end-user login on your front end, which the Users and Permissions plugin handles. Confirm current pricing and feature availability with Strapi before you decide, because plan details change.
How DeployOpen scopes, builds and hands over Strapi front-end integrations
DeployOpen connects Strapi to Next.js, Nuxt, Astro or mobile apps inside your own infrastructure, working from a written scope. Each engagement covers content fetching, preview, caching, revalidation and API design, with documentation and a handover your team can run.
How we scope
- Engagements are fixed-scope, with the front-end framework, API style and content types agreed in writing first
- The written scope lists which pages, components and content types the front end reads and writes
- Preview, caching and revalidation behavior are defined in the scope before any build work starts
- Ask for the hosting target for both Strapi and the front end, since each affects the integration design
How we build
- Build REST or GraphQL endpoints with permissions limited to what each front end actually reads
- Implement preview and draft access for editors, then test it against published and draft content
- Configure caching and revalidation triggers so content edits reach the front end on a defined path
- Test response shapes, error handling and performance of the front end against the agreed API design
How we hand over
- Deliver written documentation of API endpoints, token scopes, environment variables and revalidation flows
- Walk your engineers through the codebase, preview setup and how to add a new content type to the front end
- Confirm with your team which deployment, rollback and secret-rotation steps they will own after handover
- Record the final configuration so your team can reproduce the integration in a new environment
How we support
- Ongoing support, upgrades and continuous testing are available as retainers after handover
- Support can cover Strapi minor releases and front-end framework updates that affect the integration
- Ask whether a retainer covers response times and what it excludes before you sign
- Agree in writing who handles integration incidents, the front end, Strapi or the hosting platform

