Next.js in standalone mode
The Next.js built image can be quite large, easily exceeding 500MB. If you encounter issues with the image size, you can try “standalone” mode.
Standalone mode can significantly reduce your image size:
- At the time of writing a fresh Next.js build image is 547MB,
- A standalone image is 200MB.
Enable standalone mode:
1. Add the following to your next.config.js
file:
module.exports = {
output: 'standalone',
}
or in next.config.mjs
:
const nextConfig = {
output: 'standalone',
};
2. Add node_modules
to the .slugignore
file
This will prevent the node_modules
directory from being included in the image.
3. Set start script in the package.json
Start the server using Node.js.
{
"scripts": {
"start": "node .next/standalone/server.js"
// others scripts
}
}
4. Finally, copy assets
As indicated in the Next.js documentation, it doesn’t copy assets, so it’s up to us to copy them. To accomplish this, we can create a script that runs at build time to copy the assets to the correct location.
Create a file called copy-assets.js
in the root of your project with the following content:
const fs = require('fs').promises;
const path = require('path');
const staticSrcPath = path.join(__dirname, '.next/static');
const staticDestPath = path.join(__dirname, '.next/standalone/.next/static');
const publicSrcPath = path.join(__dirname, 'public');
const publicDestPath = path.join(__dirname, '.next/standalone/public');
function copyAssets(src, dest) {
return fs.mkdir(dest, { recursive: true })
.then(() => fs.readdir(src, { withFileTypes: true }))
.then(items => {
const promises = items.map(item => {
const srcPath = path.join(src, item.name);
const destPath = path.join(dest, item.name);
if (item.isDirectory()) {
return copyAssets(srcPath, destPath);
} else {
return fs.copyFile(srcPath, destPath);
}
});
return Promise.all(promises);
})
.catch(err => {
console.error(`Error: ${err}`);
throw err;
});
}
const greenTick = `\x1b[32m\u2713\x1b[0m`;
const redCross = `\x1b[31m\u274C\x1b[0m`;
copyAssets(staticSrcPath, staticDestPath)
.then(() => copyAssets(publicSrcPath, publicDestPath))
.then(() => console.log(`${greenTick} Assets copied successfully`))
.catch(err => console.error(`${redCross} Failed to copy assets: ${err}`));
Update package.json to run the script at build time:
{
"scripts": {
"build": "next build && node copy-assets.js",
// other scripts
}
}
Your full scripts
property of your package.json
should now look like this:
{
// other properties
"scripts": {
"dev": "next dev",
"build": "next build && node copy-assets.js",
"start": "node .next/standalone/server.js",
"lint": "next lint"
},
// other properties
}
Sample application
You can find a sample application here: https://github.com/Scalingo/sample-nextjs-standalone.