#Standalone build, turbopack vs webpack outputs are different. (mono repo)
1 messages · Page 1 of 1 (latest)
Hi @vestal lion. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
You're correct that there are differences in the output structure and contents when building a Next.js monorepo project with Webpack versus Turbopack, especially when using the standalone output mode.
Webpack Standalone Output
When building with Webpack, the .next/standalone directory typically contains only the minimal set of files required to run your app in production. This includes:
server.jsat the root of.next/standalone(or within your app's subdirectory in a monorepo)- The necessary JavaScript files and dependencies
- No extra files that aren't needed for production
This behavior is well-documented and expected. The output is generally clean and only includes what is strictly necessary for deployment. If you need static assets or the public directory, you must copy them manually as described in the docs:
cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/
Next.js Standalone Output Docs
Turbopack Standalone Output
With Turbopack, users have reported that the standalone output can include more files than expected, sometimes even files that aren't JavaScript or aren't needed for production. This includes:
- The output structure may replicate the full path to your app inside the monorepo (e.g.,
.next/standalone/apps/my-app/server.js). - Extra files, sometimes including files that shouldn't be part of the production bundle, are copied into the standalone directory.
This behavior is confirmed in several issues:
- The folder structure is intentionally nested to ensure all dependencies (including those from multiple
node_moduleslevels in a monorepo) are available, but this can result in more files being included than with Webpack. The reasoning is to ensure the app can run standalone without missing dependencies, but it can lead to confusion and bloat in the output folder.
See explanation here - There are reports that Turbopack sometimes copies files that shouldn't be included, and the output is less "clean" compared to Webpack.
See user reports here
Summary
- Webpack: Produces a minimal, clean standalone output.
- Turbopack: May produce a more verbose output, including extra files and a nested directory structure, especially in monorepos. This is by design to ensure all dependencies are present, but it can include files that aren't strictly necessary.
If you want a minimal output with Turbopack, you may need to manually clean up the output or adjust your build scripts. This is a known gap and area of ongoing improvement in Turbopack compared to Webpack.
If you need a workaround, some users have written post-build scripts to move or clean up files in the standalone directory after the build process to match their deployment needs
Example workaround.
If you need more precise control or a minimal output, Webpack may currently be the more predictable choice for standalone builds in monorepos.
If you have a specific example or want to share your output structure, I can help interpret it further based on the above findings.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@vestal lion Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@quick gorge can i use the new build adapter system to only keep the needed files?
Let me check the knowledge base for you again. Give me one moment! :books:
Yes, you can use the new experimental build adapter system in Next.js to process the build output and potentially remove or move files after the build completes. The adapter API provides an onBuildComplete hook, which gives you access to the build outputs and allows you to implement custom logic, such as cleaning up unnecessary files or restructuring the output directory.
Here’s a minimal example of how an adapter can be structured:
/** @type {import('next').NextAdapter} */
const adapter = {
name: 'my-custom-adapter',
async onBuildComplete({
outputs,
projectDir,
distDir,
// ...other context
}) {
// Custom logic here: e.g., remove or move files in distDir
// You have access to outputs.pages, outputs.appPages, etc.
},
}
module.exports = adapter
To use your adapter, set it in your next.config.js:
const nextConfig = {
experimental: {
adapterPath: require.resolve('./my-adapter.js'),
},
}
module.exports = nextConfig
This system is designed for deployment platforms or custom build integrations that need to process or modify the build output, so it is suitable for your use case of keeping only the needed files. However, the documentation does not provide a ready-made solution for file pruning—you will need to implement the logic yourself in the adapter’s onBuildComplete method.
See official documentation for details and examples
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@vestal lion Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@quick gorge how do you set the output dir now since they are seperate folders?
Let me check the knowledge base for you again. Give me one moment! :books:
In the latest versions of Next.js (v16+), the development and production build outputs are separated by default using the isolatedDevBuild feature. This means:
- The development server (
next dev) writes its output to.next/dev - The production build (
next build) writes to.next
If you want to customize the output directory for production builds, you can use the distDir option in your next.config.js:
module.exports = {
distDir: 'build', // or any directory name you prefer
}
This will cause next build to output to the specified directory instead of the default .next folder. Note that distDir should not point outside your project directory distDir documentation.
The separation of dev and build outputs is handled automatically, and you do not need to manually set different directories for dev and prod—Next.js manages this for you with the isolatedDevBuild feature, which is enabled by default isolatedDevBuild documentation.
If you want to opt out of this separation, you can set:
const nextConfig = {
experimental: {
isolatedDevBuild: false,
},
}