Chris.luChris.lu header image, displaying an 80s style landscape and sunset

Introduction

The tutorial is about adding MDX support to a Next.js 15 (and React 19) project because MDX pages can be great to create a developer portfolio, a documentation website, a blog and a lot more. To achieve this we will add several features through MDX (remark / rehype) plugins, like code highlighting, automatic table of contents generation, github flavored markdown and alerts, frontmatter, and a few more. But the tutorial goes beyond adding MDX support, as it contains several chapters about, improving security (for example by adding a content security policy (CSP) header), speed optimizations that will improve your web vital metrics.

The tutorial is also about creating a solid static first core, where we use static site generation (SSG) to generate our pages at build time, to avoid Server Side Rendering (SSR) at run time as much as possible. Pre-rendering (parts of) your pages at built time (when deploying), will minimize the amount of SSR and lead to decreased loading times as well as decreased load on your servers. Beyond this tutorial, I recommend looking into Next.js 15 features like Partial Pre-rendering (PPR) (experimental) and component streaming (in Next.js 15 using React 19 suspend) to add in dynamic parts, but also Incremental Static Regeneration (ISR).

We will also make sure the project includes features that hopefully increase your (our teams) developer experience (DX), like using the Typescript (VSCode autocomplete, type information), by setting up linting support using ESLint v9 and flat config files (with no RC compatibility mode), by adding extensions to VSCode to improve linting while you code or write markdown (in MDX files). We will use Vercel for our deployment (CI/CD and hosting) needs (feel to replace that part with a deployment on GitHub pages (setting Next.js "output" configuration option to "export") or you could self host your project (Next.js 15 comes with some improvements for self hosting). We will also add error logging and CSP violations logging using Sentry.io (again if you prefer to use another service, you can swap that part out and use your preferred solution instead).

Note

I tried to make this tutorial as beginner-friendly as possible, but also complete enough to be helpful for senior developers

This tutorial is partially based on my experience building chris.lu (the source code of my blog be found in my chris.lu repository on GitHub). I mention this because it allowed me to test the performance in production (with real visitors from all around the world). So hopefully after reading this tutorial you will be able to build your own and get a great lighthouse score, too:

lighthouse analysis results showing a 100% score for performance, accessibility, best practices, SEO

Contributing & Questions

Any contributions are always welcome 🙂. If you have a question feel free to ask on the discussion page and if you find a bug please report it using the issues (PRs for any open Issue are welcome too, if unsure about your PR, ask in the ticket first).

Source code

All the source code for this tutorial can be found in the next-js-static-first-mdx-starterkit repository on GitHub, every chapter of this tutorial is a separate branch in the repository (over time I will probably not keep each branch updated, but I will try to keep the main branch updated for a while and of course PRs are welcome 😉).

If you are migrating to Next.js 15 and React 19

After transitioning from the pages router to the app router in Next.js 14, yes we are now back at updating the core of our project because of changes in Next.js 15, but hey look at all the goodies we get 🤩.

migration steps

  1. if you are migrating a project that uses a previous version of Next.js, then you probably want to first create a new branch (or at least make sure you have no uncommitted changes)
  2. then we need to update the version of our dependencies (in our package.json)

Next.js 15 has a nice command that will check out your project and depending on its findings it will suggest codemods to use:

npx @next/codemod@canary upgrade latest

Or if you prefer use a custom command, similar to this:

npm i next@latest react@latest react-dom@latest --save-exact

and if you use Typescript, update the the React and React-dom types too:

npm i @types/react@latest @types/react-dom@latest --save-exact --save-dev

Or yet another solution is to use the versionlens for VSCode extension, which is a great extension for quick version updates

  1. next we will use Codemods (automated code transformations) to speed up the transition from an older version to Next.js 15. Codemods are little helpers that can speed up the migration process by going through your existing code, finding places where you use a feature that needs to get updated and finally upgrade those parts of your code for you. One such example are cookies, which were previously synchronous functions but are now asynchronous functions (cookies are now in the "dynamic APIs" family). Having to await cookies is a breaking change that will require you to upgrade your code. The good news is that Next.js 15 codemods can help with that. The the Next.js "Upgrading: Version 15" documentation is worth reading too, as it has information that can potentially save you a lot of time during the migration to Next.js 15
  2. same for React 19, you will likely have to do some updates in your code, like converting React 18 components using forwardRef to React 19 components using the ref that is now in component props, but again to speed things up you might want to first give the codemods a try: React 19 codemods and check out their official React 19 upgrade guide
  3. before starting to try out new features, getting your project back to building without errors, then adjust to changes like new caching semantics
  4. now you can start to add some of the new features like converting your Next.js configuration file to a typescript (next.config.ts) file, convert a regular React 18 form with an API request on submit to a React 19 version that uses server functions, or try TurboPack in development to decrease your dev build time
Note

regarding ESLint v9 and flat config files, this is something that is covered in the upcoming ESLint setup page)

Tip

I have more details about the changes you can expect when upgrading to Next.js 15 and React 19 in my The road to Next.js 15 and React 19 post.

Not all Next.js 15 (and Turbopack) features are stable

There are a few features that I could NOT use in this tutorial or had to disable and I wanted you to be aware of it before we start with the actual tutorial

Next.js 14 version of this tutorial

If you don't plan on migrating just yet and still use Next.js 14 then know that I also have a Next.js 14 version of this tutorial

The Next.js 14 version covers the same topics but there some differences in the content due to the changes that happened between Next.js 14 and Next.js 15