When working on a complex project with both Storybook and Next.js, you might run into issues during the build process. I recently hit a frustrating roadblock when my Next.js build started compiling Storybook files. It turned out that the build was trying to process *.stories.* files, which shouldn’t have been included. To avoid such conflicts, I found a way to use a separate TypeScript configuration for builds, and this guide will walk you through how I did it.
Thank me by sharing on Twitter 🙏
Here’s how you can streamline your Next.js build process by configuring it to use a dedicated tsconfig.build.json while keeping your default tsconfig.json intact for development and linting in VSCode.
Why Use a Separate TypeScript Config for Builds?
In any real-world project, you often end up with configurations or files that you only need during development but not during production. Storybook, for example, is invaluable for building and testing components, but its files don’t belong in the production build. Using a separate tsconfig.build.json allows you to:
1. Exclude non-essential files (like Storybook stories) from production builds.
The Nvidia Way: Jensen Huang and the Making of a Tech Giant
$17.50 (as of January 21, 2025 11:31 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)The Art and Making of Arcane (Gaming)
$64.47 (as of January 21, 2025 11:31 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Start with Why: How Great Leaders Inspire Everyone to Take Action
$10.49 (as of January 21, 2025 11:31 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)2. Keep development tools running smoothly—VSCode will still use tsconfig.json to lint everything, including the excluded files.
3. Avoid build errors caused by Storybook dependencies being processed by Next.js.
This configuration saves you time and ensures your build stays clean and efficient.
Setting up the Project Structure
Before making any changes, here’s what the project structure looks like:
/my-app
├── .storybook/
├── components/
│ └── Button.tsx
│ └── Button.stories.tsx
├── pages/
├── tsconfig.json
├── tsconfig.build.json
├── next.config.js
• The tsconfig.json file is used for development (including VSCode).
• tsconfig.build.json will be the version Next.js refers to when building the app.
• The .stories.tsx files should only affect Storybook and not production.
Step 1: Create a tsconfig.build.json
First, create a tsconfig.build.json file in the root of your project. This file will extend the settings from tsconfig.json but exclude files that don’t belong in the production build.
{
"extends": "./tsconfig.json",
"exclude": [
"**/*.stories.tsx",
"**/*.stories.jsx",
"**/*.stories.mdx",
"**/*.test.tsx",
"**/*.test.ts"
]
}
This configuration tells TypeScript to inherit all settings from your main tsconfig.json but skip any stories and test files during the build. These files are not necessary for production and might introduce unwanted dependencies or errors.
Step 2: Modify the next.config.js File
The next step is to make Next.js use the new tsconfig.build.json during the build process. This is as simple as adding a configuration option in the next.config.js file.
Here’s what the next.config.js file looks like after the change:
module.exports = {
...
typescript: {
tsconfigPath: "./tsconfig.build.json",
},
};
This tells Next.js to use tsconfig.build.json instead of the default tsconfig.json when it builds the app. With this setup, your development environment remains unaffected, and the build process runs more efficiently.
Step 3: Confirm VSCode Still Works with tsconfig.json
Since tsconfig.json remains the primary configuration file for development, VSCode will continue to lint all your files, including Storybook stories and tests. No further configuration is required for this step. You can verify that VSCode is working correctly by opening a .stories.tsx file and checking for any linting feedback.
If you run into issues, try restarting the TypeScript server in VSCode. You can do this by opening the command palette (Ctrl+Shift+P or Cmd+Shift+P on Mac) and selecting “TypeScript: Restart TS Server.”
Step 4: Run the Build to Verify
Now, it’s time to make sure everything is working as expected. Run the following command to build your project:
npm run build
If you are using Yarn, the command will be:
yarn build
During the build, Next.js will use the tsconfig.build.json configuration. You should no longer see any errors related to .stories files or other development-only dependencies.
If the build completes without issues, congratulations! You’ve successfully excluded unnecessary files from the build while keeping your development environment intact.
Troubleshooting Tips
If something isn’t working quite right, here are a few things to check:
1. Clear the .next directory:
Sometimes, Next.js caches old build artifacts. Try deleting the .next directory and rebuilding:
rm -rf .next
npm run build
2. Check your imports:
Make sure none of your production components accidentally import Storybook files. For example, ensure Button.tsx isn’t importing anything from Button.stories.tsx.
3. Restart VSCode if needed:
If you notice any issues with TypeScript linting in VSCode, try restarting the editor or the TypeScript server.
Conclusion
Splitting your TypeScript configuration into tsconfig.json for development and tsconfig.build.json for production is a simple yet powerful way to streamline your Next.js builds. It ensures that files meant only for development, like Storybook stories and tests, don’t interfere with the production build while keeping your development environment fully functional.
By making this small adjustment, I was able to resolve my build issues and avoid future headaches. Now my builds are faster, cleaner, and free from unnecessary clutter. This approach is easy to set up and can save you time and trouble, especially as your project grows in complexity.