How can I import markdown files as strings in Next.js to work on client and server side?
4 Answers
You can configure your Next.js webpack loaders to load markdown files and return them as strings, for example:
docs/home.md
# Home
This is my **awesome** home!
pages/index.js
import React from 'react';
import markdown from '../docs/home.md';
export default () => {
return (
<div>
<pre>{markdown}</pre>
<small><i>Import and render markdown using Next.js</i></small>
</div>
);
};
package.json
{
"name": "example",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"file-loader": "^1.1.6",
"next": "^4.2.1",
"raw-loader": "^0.5.1",
"react": "^16.2.0",
"react-dom": "^16.2.0"
}
}
next.config.js
module.exports = {
webpack: (config) => {
return Object.assign({}, config, {
externals: Object.assign({}, config.externals, {
fs: 'fs',
}),
module: Object.assign({}, config.module, {
rules: config.module.rules.concat([
{
test: /\.md$/,
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]',
},
},
{
test: /\.md$/,
loader: 'raw-loader',
}
]),
}),
});
}
};
When running:
$ npm run dev
Something like this would appear:
With the markdown string you can do whatever you would like. For example, process it with marksy.

- 759
- 1
- 6
- 19
Just install raw-loader
npm install --save raw-loader
then edit your next.config.js
webpack: (config) => {
config.module.rules.push({
test: /\.md$/,
use: 'raw-loader',
});
return config;
},

- 23,757
- 20
- 73
- 115

- 24,431
- 10
- 56
- 61
-
1Selected answer did not work for me. This did though! – SpaceOso Nov 03 '22 at 17:21
-
npm install --save or --save-dev? I think it should be --save-dev – SC K Jan 06 '23 at 19:11
-
1It seems [`raw-loader` has been deprecated](https://github.com/webpack-contrib/raw-loader). – Ben Jul 01 '23 at 18:26
Quicker and "Next.js way" is to use plugin next-mdx
Documentation: https://github.com/vercel/next.js/tree/canary/packages/next-mdx
// next.config.js
const withMDX = require('@zeit/next-mdx')({
extension: /\.mdx?$/
})
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'mdx']
})

- 11,395
- 8
- 76
- 90

- 4,752
- 2
- 20
- 29
-
2Documentation is now located at https://github.com/vercel/next.js/tree/canary/packages/next-mdx – rose specs Jul 04 '21 at 15:55
Updates: emit-file-loader
not strictly required, raw-loader
deprecated in favor of asset modules
Some updates to https://stackoverflow.com/a/47954368/895245 possibly due to newer developments:
- asset modules superseded
raw-loader
: https://stackoverflow.com/a/47954368/895245 No need to install any extra packages for that anyomore emit-file-loader
does not seem necessary anymore, not sure if it was needed, or if it is for something more specialized
so we can simplify things slightly to:
pages/index.js
import world from '../world.md'
export default function IndexPage() {
return <div>hello {world}</div>
}
next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.module.rules.push(
{
test: /\.md$/,
// This is the asset module.
type: 'asset/source',
}
)
return config
},
}
package.json
{
"name": "test",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "12.2.0",
"react": "17.0.2",
"react-dom": "17.0.2"
}
}
world.md
my md world
Getting it to work from Typescript
Unfortunately both raw-loader
and asset modules require a bit more work from typescript: https://github.com/webpack-contrib/raw-loader/issues/56#issuecomment-423640398 You have to create a file:
global.d.ts
declare module '*.md'
Otherwise the import will fail with:
Type error: Cannot find module '../world.md' or its corresponding type declarations.
Full example:
global.d.ts
declare module '*.md'
pages/index.tsx
import world from '../world.md'
export default function IndexPage() {
const what: string = 'my'
// Would fail on build as desired.
// const what2: int = 'world2'
return <div>hello {what} {world}</div>
}
next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.module.rules.push(
{
test: /\.md$/,
type: 'asset/source',
}
)
return config
},
}
package.json
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"type-check": "tsc"
},
"dependencies": {
"next": "v12.2.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@types/node": "12.12.21",
"@types/react": "17.0.2",
"@types/react-dom": "17.0.1",
"typescript": "4.0"
}
}
world.md
my md world

- 595
- 8
- 20

- 347,512
- 102
- 1,199
- 985