Webpack’s entry and output configurations are the bedrock of any build process, defining where your application’s code begins and where the bundled artifacts land.

Let’s see this in action. Imagine a simple React app.

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';

function App() {
  return <h1>Hello, Webpack!</h1>;
}

const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App />);

This is our starting point, the entry point. Now, how do we tell Webpack to bundle this and where to put it?

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js', // This is where Webpack starts its dependency graph
  output: {
    filename: 'bundle.js', // The name of the output file
    path: path.resolve(__dirname, 'dist'), // The directory where the output file will be placed
    clean: true, // Cleans the /dist folder before each build
  },
};

When you run npx webpack, Webpack will read webpack.config.js. It sees ./src/index.js as the entry point. It then traverses all import statements from index.js, building a dependency graph. Finally, it bundles all that code into a single file named bundle.js and places it inside a dist directory. The clean: true is a handy shortcut to ensure you don’t have stale build artifacts hanging around.

The entry property can be more than just a single file. You can define multiple entry points for different parts of your application, which can be useful for code splitting or creating separate bundles for different sections of your site.

// webpack.config.js
module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].bundle.js', // Uses the entry point name for the output filename
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
};

In this scenario, running npx webpack would produce dist/app.bundle.js and dist/admin.bundle.js. The [name] placeholder in the filename option is dynamically replaced by the key from the entry object. This pattern is crucial for managing larger projects where you might have distinct application modules.

The output configuration offers more granular control. publicPath is particularly important when your bundled assets are served from a different domain or a CDN, or when you’re dealing with hashed filenames for cache busting.

// webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.[contenthash].js', // Adds a hash based on content for cache busting
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/static/', // Tells Webpack that assets will be served from '/static/'
    clean: true,
  },
};

Here, the output filename will include a hash, like bundle.a1b2c3d4e5f6.js. The publicPath: '/static/' tells Webpack that when it generates index.html (if you’re using an HTML plugin) or when it encounters asset references, it should prepend /static/ to the asset path. So, bundle.a1b2c3d4e5f6.js would actually be referenced as /static/bundle.a1b2c3d4e5f6.js in your HTML. This is fundamental for deploying applications where the build output lives separately from your main HTML.

The path option must be an absolute path. Webpack needs to know exactly where to write the files, and path.resolve(__dirname, 'dist') is the standard way to construct an absolute path to a dist directory in the same directory as your webpack.config.js file.

When you specify an entry as a string like './src/index.js', Webpack implicitly creates an object { 'main': './src/index.js' }. This 'main' key is then used if you don’t specify a named filename pattern like [name].bundle.js. If you do use [name].bundle.js and only have a single string entry, the output file will still be main.bundle.js.

Many developers don’t realize that output.path dictates the filesystem location where the bundles are written, while output.publicPath dictates the URL prefix under which these bundles are served in a browser. They are distinct concepts, and getting them wrong is a common source of "404 Not Found" errors for your JavaScript assets after deployment, even if the build itself succeeds. The clean: true option, while seemingly simple, prevents subtle bugs where old code from previous builds might persist if filenames don’t change, leading to unexpected behavior or version mismatches.

Understanding how entry and output work together is key to controlling your build output. The next step is learning how to manage different environments or code splitting strategies.

Want structured learning?

Take the full Webpack course →