{"id":36686,"date":"2025-02-07T07:00:00","date_gmt":"2025-02-07T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=36686"},"modified":"2025-02-07T10:40:17","modified_gmt":"2025-02-07T18:40:17","slug":"images-mdx-next-js-app-router","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router","title":{"rendered":"Using Cloudinary Images in MDX With Next.js App Router"},"content":{"rendered":"\n<p>When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline content creation and encourage community contributions. MDX is especially powerful in Next.js, thanks to the new App Router structure, which allows for file-based routing combined with React Server Components.<\/p>\n\n\n\n<p>While MDX makes content writing more approachable for both developers and non-developers, many projects also need optimized image handling. This is where<a href=\"https:\/\/cloudinary.com\/\"> Cloudinary<\/a> excels. Cloudinary provides developers with the ability to store, transform, and deliver optimal images (and videos) at scale. By integrating Cloudinary images directly in MDX files, you can simplify your workflow and provide end-users with fast-loading, high-quality visuals.<\/p>\n\n\n\n<p>In this guide, we\u2019ll walk through a step-by-step process of setting up MDX in Next.js, configuring your project to support Cloudinary images, and adding components so that images in your MDX files are optimized on the fly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before following along, you should have:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Basic knowledge of Next.js (and the new App Router).<\/li>\n\n\n\n<li>A Next.js boilerplate project already set up, using the App Router (app\/ directory).<\/li>\n\n\n\n<li>A <a href=\"https:\/\/cloudinary.com\/users\/register_free\">free Cloudinary account<\/a>.<\/li>\n\n\n\n<li>Familiarity with <a href=\"https:\/\/mdxjs.com\/docs\/\">MDX<\/a> or <a href=\"https:\/\/www.markdownguide.org\/getting-started\/\">Markdown<\/a>, including how MDX can incorporate React components.<\/li>\n\n\n\n<li>A working knowledge of JavaScript\/TypeScript, Node.js, and installing `npm` packages.<\/li>\n<\/ol>\n\n\n\n<p>You\u2019ll also need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"http:\/\/node.js\">Node.js<\/a> (16 or higher is recommended).<\/li>\n\n\n\n<li>An IDE or text editor (VS Code, WebStorm, etc.).<\/li>\n\n\n\n<li>Some existing images or placeholders to test with.<\/li>\n<\/ul>\n\n\n\n<p>If you don\u2019t have these set up yet, take a moment to install Node, initialize a <a href=\"http:\/\/next.js\">Next.js<\/a> project, and <a href=\"https:\/\/cloudinary.com\/\">create a Cloudinary account<\/a>. Then, you\u2019ll be ready to continue. Please see their respective linked documentation for reference.&nbsp;&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Key Project Setup<\/h2>\n\n\n\n<p>Throughout this post, we\u2019ll assume you have a Next.js project with the following structure:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-string\">``<\/span><span class=\"hljs-string\">`\nmy-next-project\/\n\n\u00a0\u00a0\u251c\u2500 app\/\n\n\u00a0\u00a0\u2502 \u00a0 \u251c\u2500 layout.js\n\n\u00a0\u00a0\u2502 \u00a0 \u251c\u2500 page.js\n\n\u00a0\u00a0\u2502 \u00a0 \u2514\u2500 ...\n\n\u00a0\u00a0\u251c\u2500 components\/\n\n\u00a0\u00a0\u2502 \u00a0 \u251c\u2500 mdx-components.js\n\n\u00a0\u00a0\u2502 \u00a0 \u251c\u2500 ...\n\n\u00a0\u00a0\u251c\u2500 lib\/\n\n\u00a0\u00a0\u251c\u2500 public\/\n\n\u00a0\u00a0\u251c\u2500 next.config.mjs\n\n\u00a0\u00a0\u251c\u2500 package.json\n\n\u00a0\u00a0\u2514\u2500 ...\n\n`<\/span><span class=\"hljs-string\">``<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Within the app\/ folder, you have layout components and route files that Next.js uses to render pages. We\u2019ll add some new routes and MDX files to power a docs or blog section, along with Cloudinary-based images.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing Dependencies<\/h2>\n\n\n\n<p>We\u2019ll need to install packages to handle MDX in Next.js, plus a few helpful transformations and highlight tools (if you want them). In your terminal project root, run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-string\">`npm install @next\/mdx rehype-mdx-import-media rehype-pretty-code rehype-slug next-secure-headers shikiji-transformers json5`<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here\u2019s what each package is used for:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.npmjs.com\/package\/@next\/mdx\"><strong>@next\/mdx<\/strong><\/a>. Official MDX support for Next.js, letting you import and create <code>.mdx<\/code> files as pages.<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/remcohaszing\/rehype-mdx-import-media\"><strong>rehype-mdx-import-media<\/strong><\/a>. Allows MDX to handle media imports, like images or other files, within the MDX content.<\/li>\n\n\n\n<li><a href=\"https:\/\/www.npmjs.com\/package\/rehype-pretty-code\"><strong>rehype-pretty-code<\/strong><\/a>. A plugin to format and highlight code blocks in your MDX content (useful for developer documentation).<\/li>\n\n\n\n<li><a href=\"https:\/\/www.npmjs.com\/package\/rehype-slug\/v\/3.0.0\"><strong>rehype-slug<\/strong><\/a>. Automatically adds IDs to headings in your MDX, so you can create anchor links to specific sections.<\/li>\n\n\n\n<li><a href=\"https:\/\/www.npmjs.com\/package\/rehype-slug\/v\/3.0.0\"><strong>next-secure-headers<\/strong><\/a>. A utility to help secure your Next.js app by automatically adding best-practice HTTP headers.<\/li>\n\n\n\n<li><a href=\"https:\/\/www.npmjs.com\/package\/@shikijs\/transformers\"><strong>shikiji-transformers<\/strong><\/a>. Additional transformations for code syntax highlighting.<\/li>\n\n\n\n<li><a href=\"https:\/\/www.npmjs.com\/package\/json5\/v\/2.2.1\"><strong>json5<\/strong><\/a>. For parsing or handling JSON with some extended syntax features (like comments).<\/li>\n<\/ol>\n\n\n\n<p>If you do not plan to highlight code in your docs, you can remove the highlighting-related packages, but for many developer sites, they are quite handy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring Next.js for MDX<\/h2>\n\n\n\n<p>Next.js supports an extended configuration file, which is called next.config.mjs in Next. Let\u2019s look at a sample of how you might configure MDX. You\u2019ll also set up your Next.js images object to allow Cloudinary images:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">```\n\n<span class=\"hljs-comment\">\/\/ next.config.mjs<\/span>\n\nimport { env } from <span class=\"hljs-string\">'node:process'<\/span>;\n\nimport createMDX from <span class=\"hljs-string\">'@next\/mdx'<\/span>;\n\nimport { transformerNotationDiff } from <span class=\"hljs-string\">'@shikijs\/transformers'<\/span>;\n\nimport { createSecureHeaders } from <span class=\"hljs-string\">'next-secure-headers'<\/span>;\n\nimport rehypeMdxImportMedia from <span class=\"hljs-string\">'rehype-mdx-import-media'<\/span>;\n\nimport { rehypePrettyCode } from <span class=\"hljs-string\">'rehype-pretty-code'<\/span>;\n\nimport rehypeSlug from <span class=\"hljs-string\">'rehype-slug'<\/span>;\n\n<span class=\"hljs-comment\">\/**\n\n\u00a0* <span class=\"hljs-doctag\">@type<\/span> {import('next').NextConfig}\n\n\u00a0*\/<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> nextConfig = {\n\n\u00a0\u00a0reactStrictMode: <span class=\"hljs-keyword\">true<\/span>,\n\n\u00a0\u00a0pageExtensions: &#91;<span class=\"hljs-string\">'js'<\/span>, <span class=\"hljs-string\">'jsx'<\/span>, <span class=\"hljs-string\">'mdx'<\/span>, <span class=\"hljs-string\">'ts'<\/span>, <span class=\"hljs-string\">'tsx'<\/span>],\n\n\u00a0\u00a0images: {\n\n\u00a0\u00a0\u00a0\u00a0remotePatterns: &#91;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0protocol: <span class=\"hljs-string\">'https'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0hostname: <span class=\"hljs-string\">'res.cloudinary.com'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0pathname: <span class=\"hljs-string\">'\/**'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\n\u00a0\u00a0\u00a0\u00a0],\n\n\u00a0\u00a0},\n\n\u00a0\u00a0webpack: (config, { isServer }) =&gt; {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Example: if you have custom server plugins, you can push them here<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">if<\/span> (isServer) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Potential server-only code or plugins<\/span>\n\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> config;\n\n\u00a0\u00a0},\n\n\u00a0\u00a0async headers() {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Using next-secure-headers to add recommended security headers<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> &#91;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0source: <span class=\"hljs-string\">'\/(.*)'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0headers: createSecureHeaders({\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0xFrameOptions: <span class=\"hljs-string\">'SAMEORIGIN'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0xContentTypeOptions: <span class=\"hljs-string\">'nosniff'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ ... other header settings<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}),\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\n\u00a0\u00a0\u00a0\u00a0];\n\n\u00a0\u00a0},\n\n};\n\n<span class=\"hljs-keyword\">const<\/span> withMDX = createMDX({\n\n\u00a0\u00a0extension: \/\\.mdx?$\/,\n\n\u00a0\u00a0options: {\n\n\u00a0\u00a0\u00a0\u00a0rehypePlugins: &#91;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0rehypeMdxImportMedia,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0rehypeSlug,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#91;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0rehypePrettyCode,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0transformers: &#91;transformerNotationDiff()],\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0theme: <span class=\"hljs-string\">'github-dark-dimmed'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0defaultLang: <span class=\"hljs-string\">'plaintext'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0],\n\n\u00a0\u00a0\u00a0\u00a0],\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ add any remark plugins here if needed<\/span>\n\n\u00a0\u00a0},\n\n});\n\nexport <span class=\"hljs-keyword\">default<\/span> withMDX(nextConfig);\n\n```<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code block above, here are what the key sections are for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>pageExtensions<\/code><\/strong>. Allows Next.js to process <code>.mdx<\/code> files as pages.<\/li>\n\n\n\n<li><strong><code>images<\/code><\/strong> <strong>object<\/strong>. We explicitly list Cloudinary as a remote pattern, so Next.js knows to optimize and host images from res.cloudinary.com. Adjust the hostname or pathname as needed.<\/li>\n\n\n\n<li><strong><code>withMDX<\/code><\/strong>. The <code>@next\/mdx<\/code> wrapper adds MDX-specific configuration. We specify the file extensions and pass rehype plugins for extra functionality, like syntax highlighting with <code>rehypePrettyCode<\/code>.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Cloudinary Setup and Environment Variables<\/h2>\n\n\n\n<p>Before you begin embedding images in .mdx files, make sure you have:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>A Cloudinary account where your images or folders reside.<\/li>\n\n\n\n<li>A Cloud name, API key, and API secret (if you plan to do programmatic uploads). For the simplest usage (just referencing existing images by URL), you only need your cloud name.<\/li>\n<\/ol>\n\n\n\n<p>You can store your keys in environment variables. To do so, create a <code>.env.local<\/code> file in your Next.js root then add these keys and values:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">CLOUDINARY_CLOUD_NAME=your_cloud_name\n\nCLOUDINARY_API_KEY=123456789012345\n\nCLOUDINARY_API_SECRET=abcdefg-hijklmnop<\/code><\/span><\/pre>\n\n\n<p>If all you plan to do is embed images by static URL (e.g., <code>https:\/\/res.cloudinary.com\/&lt;cloud_name>\/image\/upload\/...)<\/code>, you don\u2019t need the API key or secret. However, including them can help if you want to use server-side transformations, automated image fetching, or advanced features.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating MDX Files and Embedding Images<\/h2>\n\n\n\n<p>With your Next.js App Router, you can place MDX files directly in subfolders under app\/ to define routes, or store them in a dedicated app\/docs\/ folder. For example:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfVMpPyTtOQy74_V4vQ79tl6QWrOlfn_3rWUMI0rt9_4BBu6oLeBC6X6nAN489Y0DZ1DjVNQYO69kwz1iuO0KVr5b3tbxYn77k6hdjnILBKw5JMS-Uf08hiJRICKpzVUhfnYtJcRQ?key=ghhGIfTKexQA0ESnO3Nj1RDe\" alt=\"\"\/><\/figure>\n\n\n\n<p>Inside <code>page.mdx<\/code>, you can add your content in Markdown\/MDX format. Let\u2019s illustrate how to embed a Cloudinary image:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">```markdow\/mdx file\n\n---\n\ntitle: <span class=\"hljs-string\">'Introduction'<\/span>\n\ndate: <span class=\"hljs-string\">'2025-01-24'<\/span>\n\n---\n\n<span class=\"hljs-comment\"># Introduction to Our Docs<\/span>\n\nWelcome! This is a test **MDX** file <span class=\"hljs-keyword\">for<\/span> verifying our Cloudinary image embedding.\n\nBelow is an example image, served directly from Cloudinary:\n\n!&#91;A Cloudinary Example](https:<span class=\"hljs-comment\">\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/image\/upload\/v1670000000\/sample.jpg)<\/span>\n\nYou can also embed inlined images <span class=\"hljs-keyword\">or<\/span> dynamic transformations using query parameters, <span class=\"hljs-keyword\">for<\/span> example:\n\n!&#91;A Transformed Example](https:<span class=\"hljs-comment\">\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/image\/upload\/w_500,h_300,c_fill\/v1670000000\/sample.jpg)<\/span>\n\n```<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here, we are using standard Markdown syntax for images (<code>![Alt Text](URL)<\/code>), though you could also import them as modules or use a custom React component. As soon as you add these .mdx files and run <code>npm run dev<\/code> (or your build command), Next.js will treat them like any other page in the App Router structure.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Closer Look at Next.js App Router<\/h2>\n\n\n\n<p>The Next.js 13 App Router organizes pages via nested folders inside app\/. Each folder can contain a page.js, page.tsx, or page.mdx (as we\u2019ve just done), which exports the UI for that route.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Layout Files<\/strong>. layout.js or layout.tsx can define shared layouts or wrappers for each segment of the route.<\/li>\n\n\n\n<li><strong>page.js<\/strong> or `<code>.mdx**<\/code>. The actual content or React components that define the UI for that path.<\/li>\n<\/ul>\n\n\n\n<p>If your docs hierarchy grows, you might nest subfolders like so:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfuDOCjgOdS39pWm_Wi7IDDQSSdoLjY2POHm3hmnRiRNY7Uf67KDNQxFb650E1KpinHke9yQg9kDRbKitKPECRjUSjd-U-Ia145aQFKOMNddfU5ybvcrhtmZfjaOJUTptMtAod57w?key=ghhGIfTKexQA0ESnO3Nj1RDe\" alt=\"\"\/><\/figure>\n\n\n\n<p>Each directory with a <code>page.mdx<\/code> automatically becomes a route:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>\/docs\/quickstart\/<\/code><\/li>\n\n\n\n<li><code>\/docs\/introduction\/<\/code><\/li>\n<\/ul>\n\n\n\n<p>This approach is extremely powerful for a developer relations or documentation site, as you can keep all your MDX files in one place without complicated routing logic.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Global MDX Components (Replacing &lt;img> With Next.js &lt;Image>)<\/h2>\n\n\n\n<p>One of the powerful features of MDX is the ability to override default HTML elements with React components. For instance, you can globally replace &lt;img&gt; with Next.js\u2019s native &lt;Image&gt; component to get automatic optimization, lazy loading, and more.<\/p>\n\n\n\n<p>Create a file called <code>mdx-components.js<\/code> (or <code>.tsx<\/code>) in your components\/ folder:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">```markdow\/mdx file\n\n---\n\ntitle: <span class=\"hljs-string\">'Introduction'<\/span>\n\ndate: <span class=\"hljs-string\">'2025-01-24'<\/span>\n\n---\n\n<span class=\"hljs-comment\"># Introduction to Our Docs<\/span>\n\nWelcome! This is a test **MDX** file <span class=\"hljs-keyword\">for<\/span> verifying our Cloudinary image embedding.\n\nBelow is an example image, served directly from Cloudinary:\n\n!&#91;A Cloudinary Example](https:<span class=\"hljs-comment\">\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/image\/upload\/v1670000000\/sample.jpg)<\/span>\n\nYou can also embed inlined images <span class=\"hljs-keyword\">or<\/span> dynamic transformations using query parameters, <span class=\"hljs-keyword\">for<\/span> example:\n\n!&#91;A Transformed Example](https:<span class=\"hljs-comment\">\/\/res.cloudinary.com\/&lt;cloud_name&gt;\/image\/upload\/w_500,h_300,c_fill\/v1670000000\/sample.jpg)<\/span>\n\n```<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In your root layout or a dedicated provider file, import this <code>useMDXComponents<\/code> function to let Next.js know how to interpret elements in your MDX:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">```\n<span class=\"hljs-comment\">\/\/ app\/layout.js (or wherever you manage MDX context)<\/span>\n\nimport <span class=\"hljs-string\">'.\/globals.css'<\/span>; <span class=\"hljs-comment\">\/\/ example CSS import<\/span>\n\nimport { useMDXComponents } from <span class=\"hljs-string\">'@\/components\/mdx-components'<\/span>;\n\nimport { MDXProvider } from <span class=\"hljs-string\">'@mdx-js\/react'<\/span>;\n\nexport <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">RootLayout<\/span><span class=\"hljs-params\">({ children })<\/span> <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> mdxComponents = useMDXComponents({});\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0&lt;html lang=<span class=\"hljs-string\">\"en\"<\/span>&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;body&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;MDXProvider components={mdxComponents}&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{children}\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/MDXProvider&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/body&gt;\n\n\u00a0\u00a0\u00a0\u00a0&lt;\/html&gt;\n\n\u00a0\u00a0);\n\n}\n\n```<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, any &lt;img> tags you place in <code>.mdx<\/code> files become Next.js &lt;Image> components automatically, allowing you to serve Cloudinary images with built-in optimizations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Functionality<\/h3>\n\n\n\n<p>With the configurations in place, run this command in your terminal:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">npm run dev<\/code><\/span><\/pre>\n\n\n<p>Visit one of your MDX-defined routes, such as <code>\/docs\/introduction\/<\/code>.<\/p>\n\n\n\n<p>Observe how the page loads your Cloudinary-hosted images. If you open your browser\u2019s network tab, you\u2019ll see that images load from res.cloudinary.com, potentially with additional query parameters if you set transformations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Production Build<\/h2>\n\n\n\n<p>If you want to see how everything runs in production mode:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-string\">``<\/span><span class=\"hljs-string\">`\n\nnpm run build\n\nnpm run start\n\n`<\/span><span class=\"hljs-string\">``<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next.js will compile your MDX files, ensuring the pages function the same, but with production optimizations. Cloudinary images will be optimized, sized, and delivered in next-gen formats when possible (e.g., <a href=\"https:\/\/developers.google.com\/speed\/webp\/docs\/using\">WebP<\/a>) to browsers that support them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dynamic Transformations with Cloudinary<\/h2>\n\n\n\n<p>One of Cloudinary\u2019s biggest draws is the ability to transform images on the fly. For instance, specifying <code>w_300,h_200,c_fill<\/code> (width=300, height=200, crop=fill) will automatically resize and crop. If you want to use these transformations in your MDX images, simply append them to the URL:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">`!&#91;Transformed Example](<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/\"<\/span>&gt;<\/span>https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/image\/upload\/w_300,h_200,c_fill\/v1670000000\/sample.jpg)`<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Or if you want advanced usage, you can build a custom server-side route in Next.js to sign transformation requests using your Cloudinary API credentials. However, for many docs or blog scenarios, simply building the transformations into the URL is sufficient.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Potential Advanced Patterns<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Custom route for images<\/strong>. If you need more fine-tuned control over transformations, you could create an API endpoint (e.g., <code>app\/api\/images\/route.js<\/code>) to fetch images from Cloudinary with secret transformations or dynamic logic based on user input.<\/li>\n\n\n\n<li><strong>Cloudinary plugins<\/strong>. The <a href=\"https:\/\/github.com\/cloudinary\/cloudinary_npm\">Cloudinary npm package<\/a> allows you to manage resources, handle upload widgets, or serve advanced transformations in React. You can incorporate these into your Next.js server or client components as needed.<\/li>\n\n\n\n<li><strong>MDX metadata<\/strong>. Notice that at the top of your <code>.mdx<\/code> file, you can define metadata. Next.js\u00a0also provides a metadata export that can help define page titles, meta tags, or open graph tags. Explore how you might unify MDX front matter with Next.js metadata for consistent SEO across your documentation site.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Integrating Cloudinary with MDX in Next.js offers a powerful setup for developer-focused sites. You benefit from:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Streamlined content creation<\/strong>. MDX lets you write rich, Markdown-style documentation with embedded React components and easy collaboration.<\/li>\n\n\n\n<li><strong>Optimized image delivery<\/strong>. Cloudinary automatically serves the best formats and sizes, speeding up load times and improving UX.<\/li>\n\n\n\n<li><strong>Scalable file structure<\/strong>. The Next.js App Router organizes your docs or blog routes so that each .mdx file becomes a page. You don\u2019t need a complicated custom routing system.<\/li>\n<\/ol>\n\n\n\n<p>When combining these tools, you have a flexible environment that can handle both text-based content and high-quality, performant images \u2014 perfect for hosting everything from code snippets and design assets to large blog images or developer guides. By overriding default &lt;img&gt; elements with Next.js &lt;Image&gt;, you ensure that every Cloudinary-served image can be transformed or optimized on demand.<\/p>\n\n\n\n<p><a href=\"https:\/\/cloudinary.com\/users\/register_free\">Sign up<\/a> for a free Cloudinary account today.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline content creation and encourage community contributions. MDX is especially powerful in Next.js, thanks to the new App Router structure, which allows for file-based routing combined with React Server Components. While [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":36687,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[390,134,212],"class_list":["post-36686","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-app","tag-guest-post","tag-next-js"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Using Cloudinary Images in MDX With Next.js App Router<\/title>\n<meta name=\"description\" content=\"When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Cloudinary Images in MDX With Next.js App Router\" \/>\n<meta property=\"og:description\" content=\"When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-07T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-07T18:40:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next-js_App_Router-jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Using Cloudinary Images in MDX With Next.js App Router\",\"datePublished\":\"2025-02-07T15:00:00+00:00\",\"dateModified\":\"2025-02-07T18:40:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\"},\"wordCount\":1577,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA\",\"keywords\":[\"app\",\"Guest Post\",\"Next.js\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\",\"url\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\",\"name\":\"Using Cloudinary Images in MDX With Next.js App Router\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA\",\"datePublished\":\"2025-02-07T15:00:00+00:00\",\"dateModified\":\"2025-02-07T18:40:17+00:00\",\"description\":\"When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Cloudinary Images in MDX With Next.js App Router\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Using Cloudinary Images in MDX With Next.js App Router","description":"When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router","og_locale":"en_US","og_type":"article","og_title":"Using Cloudinary Images in MDX With Next.js App Router","og_description":"When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline","og_url":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router","og_site_name":"Cloudinary Blog","article_published_time":"2025-02-07T15:00:00+00:00","article_modified_time":"2025-02-07T18:40:17+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next-js_App_Router-jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Using Cloudinary Images in MDX With Next.js App Router","datePublished":"2025-02-07T15:00:00+00:00","dateModified":"2025-02-07T18:40:17+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router"},"wordCount":1577,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA","keywords":["app","Guest Post","Next.js"],"inLanguage":"en-US","copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router","url":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router","name":"Using Cloudinary Images in MDX With Next.js App Router","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA","datePublished":"2025-02-07T15:00:00+00:00","dateModified":"2025-02-07T18:40:17+00:00","description":"When you build a developer-focused site \u2014 whether it\u2019s documentation, a personal blog, or a knowledge base \u2014 using MDX (Markdown with JSX) can streamline","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/images-mdx-next-js-app-router#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using Cloudinary Images in MDX With Next.js App Router"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1738367723\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router\/Using_Cloudinary_Images_in_MDX_with_Next.js_App_Router.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36686","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=36686"}],"version-history":[{"count":1,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36686\/revisions"}],"predecessor-version":[{"id":36688,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36686\/revisions\/36688"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/36687"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=36686"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=36686"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=36686"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}