karma.conf.js is the single source of truth for how Karma runs your tests. This lesson walks through its structure section by section so you can confidently read and modify any configuration you encounter.
The Shape of karma.conf.js
Every karma.conf.js file exports one function. Karma calls that function once, at startup, passing in a config object with helper methods (like config.set()) and constants (like config.LOG_INFO). Inside the function, you build up a single options object and hand it to config.set().
Because it's a real JavaScript file (not JSON or YAML), you can use conditionals, environment variables, and require() freely — a common pattern is branching on process.env.CI to change browsers or reporters between local development and continuous integration.
Because the file is plain JavaScript, branching logic like this isCI check is completely normal and encouraged.
Commonly Used config.set() Options
config.set({
basePath: '', // resolves relative paths
frameworks: [], // e.g. ['jasmine']
files: [], // files/patterns to load
exclude: [], // patterns to exclude
preprocessors: {}, // transform files before serving
reporters: [], // e.g. ['progress']
port: 9876, // server port
colors: true, // colorized terminal output
logLevel: config.LOG_INFO, // verbosity
browsers: [], // e.g. ['ChromeHeadless']
autoWatch: true, // rerun on file changes
singleRun: false, // exit after one run
concurrency: Infinity // parallel browser limit
});
config.LOG_INFO, config.LOG_DEBUG, etc. are constants provided on the config object itself.
Every option has a sensible internal default; you only need to override what your project requires.
Order inside config.set() doesn't matter functionally, but grouping related options improves readability.
You can call config.set() more than once if you build the object incrementally, though most projects call it once.
karma.conf.js Options Cheat Sheet
The options you'll touch in almost every project.
Option
Purpose
basePath
Root directory relative paths are resolved against
frameworks
Which adapter(s) provide test syntax
files
Which files/globs get served to the browser
exclude
Patterns to exclude from files matches
preprocessors
Transform matched files before serving (e.g. webpack)
reporters
Which reporter plugin(s) format output
port
Local server port (default 9876)
browsers
Which launcher(s)/browser(s) to run tests in
singleRun
Exit after one run instead of watching
autoWatch
Rerun tests automatically when files change
How Karma Finds and Loads the Config File
By default, karma start looks for karma.conf.js in the current working directory. You can point it at a different file explicitly, which is how many projects maintain separate configs for local development versus CI.
For projects that need meaningfully different local vs. CI behavior, a common pattern is a base config file that exports shared settings, imported and extended by environment-specific files.
This keeps shared settings in one place while letting CI-specific settings live separately and explicitly.
Common Mistakes
Forgetting the file must export a function, not a plain options object.
Calling config.set() with an incomplete object and assuming Karma merges deeply where it actually replaces top-level keys.
Duplicating an entire config for CI instead of sharing common settings and only overriding what differs.
Not checking process.env.CI (or an equivalent flag) when local and CI environments genuinely need different browsers.
Key Takeaways
karma.conf.js exports a function that receives a config object and calls config.set().
Because it's plain JavaScript, conditional logic based on environment variables is a normal, supported pattern.
Karma looks for ./karma.conf.js by default, but any file path can be passed explicitly to karma start.
Splitting shared vs. environment-specific settings into separate files keeps larger configs maintainable.
Pro Tip
Add a one-line console.log() at the top of your config function while debugging environment-specific behavior — it's a fast, low-tech way to confirm exactly which branch of your config logic actually ran for a given invocation.
You can now read and structure karma.conf.js confidently. Next, learn how framework adapters like karma-jasmine plug into this configuration.