A minimal, production-ready starter for Next.js 15 and Craft CMS projects. Check out the features, or dive right in!
Tip
Curious about Craft, but want to try it with a different framework? We have other starter projects, too!
This project assumes you have our recommended development environment DDEV installed and up-to-date.
-
Clone this repository, and move into the new directory:
git clone https://github.com/craftcms/starter-next.git # ... cd starter-next
-
(Optional) Adjust the DDEV project name and domains. See this section for more information.
-
Set up the Craft CMS backend:
ddev composer install ddev craft install
Write down the username and password you choose, during installation. You’ll need it to log in to the control panel.
-
Generate a token for the Guestbook GraphQL schema:
# Display a list of schemas and UUIDs: ddev craft graphql/list-schemas # Use the “Guestbook” schema ID to generate a token: ddev craft graphql/create-token c7d2eb61-cdde-4a76-88a9-eb30ddcf155b
(The Guestbook schema is automatically created with the appropriate permissions via Project Config as Craft is installed, but tokens are unique to each environment.)
-
Add required Next.js configuration:
- Copy
frontend/.env.example
tofrontend/.env
; - Populate the
GRAPHQL_TOKEN
variable with the token you just generated;
- Copy
-
Install front-end dependencies and start the Next.js development server:
ddev fe npm install ddev fe npm run dev
Tip
The URLs that Next.js emits as it boots up may not work—they are correct inside their respective containers, but must be accessed from the outside via the pre-configured DDEV hostnames.
Run ddev launch
to open the front end in your default browser, or visit https://starter-next.ddev.site
.
The Craft control panel is available at https://api.starter-next.ddev.site/admin
. Log in with the username and password you created during installation!
This project includes basic support for a handful of Craft’s best features, in a tidy headless package built on Next.js 15.
Next.js communicates with Craft’s built-in GraphQL API to query posts and pages, and create (or “mutate”) guestbook entries.
Craft’s live preview works just as you’d expect. You can even copy a secure, sharable URL to any draft.
The blog, category feeds, and the guestbook are neatly paginated in a way that matches Craft’s native handling. Progress through a set of paginated results is reflected in the URL and your browser’s navigation history.
We’ve split the project directory into two folders, backend/
and frontend/
, to better demonstrate the boundaries of Craft and Next.js, respectively. Some configuration needs to be transcribed between the spaces to ensure each half understands where the other lives!
Warning
The front- and back-end .env
files are separate! Make sure you are updating configuration in the correct file.
There is no .gitignore
at the root of the project—instead, each system maintains its own relatively-vanilla file (backend/.gitignore
and frontend/.gitignore
).
The backend/
directory is predominantly a standard Craft installation, so its structure should be familiar. Craft is configured to run in headless mode, which means it doesn’t perform any element routing, nor template rendering—in fact, it will only respond to control panel, action, and static asset requests (like any images you might upload).
Craft uses the PRIMARY_SITE_URL
environment variable (automatically set by DDEV) to generate fully-qualified URLs for front-end pages, and the CRAFT_BASE_CP_URL
(predefined in backend/.env
) to build control panel and asset URLs.
Next.js lives in the frontend/
directory. All NPM commands should be executed here—as a convenience, we’ve included a custom DDEV command (.ddev/commands/web/fe
) that ensures tasks are run in the appropriate directory:
ddev fe npm install
→ Moves intofrontend/
, then executesnpm install
;ddev fe npm run dev
→ Moves intofrontend/
, then executes the user-defineddev
script;
See frontend/next.config.js
to customize Next.js, or read about the rest of its project structure.
Routing is handled primarily via the app/
directory, and GraphQL queries are centralized in queries/
.
If you want to compress the GraphQL query feedback loop, open up the Craft control panel and click GraphQL in the main navigation, then choose GraphiQL. Read more about the GraphQL IDE in the Craft documentation.
The DDEV configuration files shipped with this project use a specific pair of URLs for the Next.js front end and Craft back end:
- Front end:
https://starter-next.ddev.site
- Back end:
https://api.starter-next.ddev.com
If you would like to use different URLs, you must make a few changes in .ddev/config.yaml
:
- Update the
name
key (this influences thestarter-project
segment of the base URL); - Change the back-end hostname under the
additional_hostnames
key; - Change the
VIRTUAL_HOST
domains underweb_environment
;
Then, a change is required for each of the nginx configuration files:
- Change the
server_name
directive in.ddev/nginx_full/api-site.conf
to match the back-end url; - Change the
server_name
directive in.ddev/nginx_full/next-site.conf
to match the front-end url;
Next.js also needs to be told what front-end URLs should look like:
- Update
BASE_URL
infrontend/.env
;
Finally, Craft may need to generate absolute URLs to the control panel in some scenarios:
- Update
CRAFT_BASE_CP_URL
inbackend/.env
;
Your production configuration will probably look different—as long as Next.js knows where the GraphQL endpoint lives (CRAFT_URL
in frontend/.env
) and both Craft and Next.js know how to generate public URLs (PRIMARY_SITE_URL
in backend/.env
and BASE_URL
in frontend/.env
, respectively) these URLs don’t need to be related in any specific way!
Tip
Always validate your CORS policy when deploying projects that make cross-domain requests!
The path Next.js uses to fetch data via GraphQL must be kept in sync between backend/config/routes.php
and the apiBasePath
variable in frontend/src/lib/graphql.js
.
Pull requests are welcome. Significant structural or aesthetic changes should be submitted as an issue.