Compiler Options

Common Options


When using :main it is often necessary to control where the entry point script attempts to load scripts from due to the configuration of the web server. :asset-path is a relative URL path not a file system path. For example, if your output directory is :output-dir "resources/public/js/compiled/out" but your webserver is serving files from "resources/public" then you want the entry point script to load scripts from "js/compiled/out".

:asset-path "js/compiled/out"


When using :target :bundle, set shell commands to be run after a build. This command is not parameterizable. You should provide both :none which will be run after dev builds, and :default which will be run after builds passed through Closure Compiler. The command should be one that exits, i.e. you cannot use this to launch a watcher.

:bundle-cmd {:none ["npx" "webpack" "--mode=development"]
             :default ["npx" "webpack"]}


If set to :warn or :error, checks inferred types and runtime values passed to aget and aset. Inferred type mismatches will result in the :invalid-array-access warning being triggered. Logs when incorrect values are passed if set to :warn, throws if set to :error. May be set to a false-y value to disable this feature.

This setting does not apply if :optimizations is set to :advanced.

:checked-arrays :warn


Configure externs files for external libraries. The files are searched for in the current working directory and on the classpath.

For this option, and those below, you can find a very good explanation at:

Defaults to the empty vector [].

:externs ["jquery-externs.js"]


Adds dependencies on foreign libraries. Be sure that the url returns a HTTP Code 200.

Defaults to the empty vector []

:foreign-libs [{ :file ""
                 :provides  ["my.example"]
                 :global-exports '{my.example MyExample}}
               { :file "./resources/js/local.js"
                 :provides ["my.other.example"]}
               { :file "./path/to/directory/"
                 ;; :provides will be automatically generated based on
                 ;; each .js filename. E.g: your.dep.js file will
                 ;; provides ["your.dep"]. Custom defined :provides in
                 ;; this case will be overwritten.

Each element in the :foreign-libs vector should be a map, where the keys have these semantics:

  • :file Indicates the URL to the library. This can be either local path or remote url to the dependency file. If local path is a directory instead of a file, the compiler will recursively go through all .js files within the directory and automatically assign a :provides values based on the .js filename. E.g: your.js.deps.js results in computed :provides ["your.js.deps"], and your custom :provides will be overwritten by the generated :provides.

  • :file-min (Optional) Indicates the URL to the minified variant of the library. This will be used in preference to :file if :optimizations is set to either :simple or :advanced.

  • :provides A synthetic namespace that is associated with the library. This is typically a vector with a single string, but it has the capability of specifying multiple namespaces (typically used only by Google Closure libraries).

  • :requires (Optional) A vector explicitly identifying dependencies (:provides values from other foreign libs); used to form a topological sort honoring dependencies.

  • :module-type (Optional) indicates that the foreign lib uses a given module system. Can be one of :commonjs, :amd, :es6. Note that if supplied, :requires is not used (as it is implicitly determined). For more info see JavaScript Module Support (Alpha).

  • :preprocess (Optional) Used to preprocess / transform code in other dialects (JSX, etc.). The value can be either a symbol or a keyword. If symbol is provided, it should resolve to a function that takes two parameters: js-module and options maps. Compiler will require the namespace to which the symbol refers if it is not yet loaded. If value is keyword, it is used as dispatch value for cljs.clojure/js-transforms multimethod. For more info see JavaScript Library Preprocessing.

  • :global-exports (Optional) used to map provided namespaces to globally exported values. The keys may be symbols or strings. If present the foreign library can be used idiomatically when required, i.e. support for :refer, :rename, :as, etc.


Defaults to false. If true load goog.object and goog.array as global namespaces rather than as goog.module namespaces.


If true automatically install all declared :npm-deps including those declared in upstream dependencies.


Specifies an entry point namespace. When combined with optimization level :none, :main will cause the compiler to emit a single JavaScript file that will import goog/base.js, the JavaScript file for the namespace, and emit the required goog.require statement. This permits leaving HTML markup identical between dev and production.

Normally provided as a symbol. In an EDN config file you do not need to quote the symbol.


:main can also be provided as a string, but the former is preferred.

:main ""

Also see :asset-path.

Note: This will result in the main namespace, along with the transitive closure of all :required namespaces to be loaded into your JavaScript environment. If you have other non-referenced namespaces that need to be loaded, consider either :requireing them or manually loading them by issuing the appropriate additional goog.require statements.


A new option for emitting Google Closure Modules. Closure Modules supports splitting up an optimized build into N different modules. If :modules is supplied it replaces the single :output-to. A module needs a name, an individual :output-to file path, :entries a set of namespaces, and :depends-on a set of modules on which the module depends. An example follows:

{:optimizations :advanced
 :source-map true
 :output-dir "resources/public/js"
 :modules {
     {:output-to "resources/public/js/common.js"
      :entries #{""}}
     {:output-to "resources/public/js/landing.js"
      :entries #{""}
      :depends-on #{:common}}
     {:output-to "resources/public/js/editor.js"
      :entries #{""}
      :depends-on #{:common}}}}

Any namespaces not in an :entries set will be moved into the default module :cljs-base. However thanks to cross module code motion, Google Closure can move functions and methods into the modules where they are actually used. This process is somewhat conservative so if you know that you want to keep some code together do this via :entries.

The :cljs-base module defaults to being written out to :output-dir with the name "cljs_base.js". This may be overridden by specifying a :cljs-base module describing only :output-to.

Take careful note that a namespace may only appear once across all module :entries.

:modules fully supports :foreign-libs. :foreign-libs are always put into dependency order before any Google Closure compiled source.

Source maps are fully supported, an individual one will be created for each module. Just supply :source-map true (see example) as there is no single source map to name.


Control NPM dependencies. A map of NPM package names (keywords or strings) to the desired versions, or a Boolean value. A node_modules directory will be indexed and used if set to a truthy value. Defaults to false. (In ClojureScript 1.10.339 and earlier, defaulted to true.) See also :install-deps.

The :npm-deps feature is in alpha status for optimized builds. When applying Closure optimizations, NPM dependencies are passed through Closure Compiler and not all NPM libraries contain Closure-compatible code.

A reliable alternative can be found with ClojureScript with Webpack.

:npm-deps {"lodash" "4.17.4"}


The optimization level. May be :none, :whitespace, :simple, or :advanced. Only :none and :simple are supported for bootstrapped ClojureScript.

:none is the recommended setting for development, while :advanced is the recommended setting for production, unless something prevents it (incompatible external library, bug, etc.).

For a detailed explanation of the different optimization modes see Closure Compiler Compilation Levels.

The node.js externs may also serve as useful examples.

When the :main option is not used, :none requires manual code loading and hence a separate HTML from the other options.

Defaults to :none.

:optimizations :none


The path to the JavaScript file that will be output.

:output-to "resources/public/js/main.js"


Sets the output directory for temporary files used during compilation. Defaults to "out".

:output-dir "resources/public/js/out"


Developing ClojureScript commonly requires development time only side effects such as enabling printing, logging, and connecting REPLs. :preloads permits loading such side effect boilerplate right after cljs.core. For example you can make a development namespace for enabling printing in browsers:



Now you can configure your development build to load this side effect prior to your main namespace with the following compiler options:

{:preloads '[]
 :main 'foo.core
 :output-dir "out"}

:preloads must be a sequence of symbols that map to existing namespaces discoverable on the classpath. Note the leading quote is not necessary when using Leiningen - values in project.clj are implicitly quoted.

For :optimizations :none, a :main option must be specified for preloads to work.


Determines whether the JavaScript output will be tabulated in a human-readable manner. Defaults to false.

:pretty-print false


See Source-maps. Under optimizations :none the valid values are true and false, with the default being true. Under all other optimization settings must specify a path to where the source map will be written.

Under :none:

:source-map false


:source-map "path/to/source/"


Ensures reduced name churn between advanced builds thus proper vendorization if you’re using :modules.

:stable-names true


Valid options are :nodejs, :webworker, :bundle, and :none.

The default (no :target specified) implies browsers are being targeted.

Have a look here for more information on how to run your code in nodejs.

:webworker produces a bootstrap script suitable for loading with Web Workers.

The :bundle target is to support dependencies in node_modules. The output generated by ClojureScript will need to be passed on to some other JavaScript tool (i.e. Webpack, Metro) that can handle the Node.js style require imports generated for these dependencies.

The :none target causes output to be generated that has no dependency on any particular execution environment.

:target :nodejs


Emit details and measurements from compiler activity.

:verbose true

Less Common Options


Strategies for how the Google Closure compiler does naming of anonymous functions that occur as r-values in assignments and variable declarations. Defaults to :off.

:anon-fn-naming-policy :unmapped

The following values are supported:

  • :off Don’t give anonymous functions names.

  • :unmapped Generates names that are based on the left-hand side of the assignment. Runs after variable and property renaming, so that the generated names will be short and obfuscated.

  • :mapped Generates short unique names and provides a mapping from them back to a more meaningful name that’s based on the left-hand side of the assignment.


Defaults to true if ClojureScript is being used via cljs.main, and false otherwise or if ClojureScript is being used as a git dep. Controls whether the shared AOT cache is used for compiler artifacts produced from JARs.

:aot-cache true


Automatically inject components required by the standard browser REPL. When launching the browser REPL this default to true.

:browser-repl true


Experimental. Cache compiler analysis to disk. This enables faster cold build and REPL start up times.

For REPLs, defaults to true. Otherwise, defaults to true if and only if :optimizations is :none.

:cache-analysis true


Set the values of Closure libraries' variables annotated with @define or with the cljs.core/goog-define helper macro. A common usage is setting goog.DEBUG to false:

:closure-defines {"goog.DEBUG" false}

You can also use symbols:

:closure-defines { true}

Note when using Lein the quote is unnecessary due to implicit quoting.

For :optimizations :none, a :main option must be specified for defines to work, and only goog-define defines are affected. :closure-defines currently does not have any effect with :optimizations :whitespace.

You can use the variables set in :closure-defines to eliminate parts of your code at compile time (DCE). However, to do so you must use if or cond in combination with an identical? comparison. Any other forms (such as case or condp) will work correctly at runtime, but the javascript output will contain the dead code branches.

For example, if you want to make a localized build of your application which only contains the translation messages relevant for the locale:

(def messages
    (identical? js/goog.LOCALE "nl")
    (identical? js/goog.LOCALE "fr")
    :else i18n.en/messages))


Define extra JSDoc annotations that a closure library might use so that they don’t trigger compiler warnings.

:closure-extra-annotations #{"api"}


Configure the output character set. May be:

  • iso-8859-1

  • us-ascii

  • utf-16

  • utf-16be

  • utf-16le

  • utf-8

Defaults to utf-8

:closure-output-charset "iso-8859-1"


Configure warnings generated by the Closure compiler. A map from Closure warning to configuration value, only :error, :warning and :off are supported.

:closure-warnings {:externs-validation :off}

The following Closure warning options are exposed to ClojureScript:


See the Closure Compiler Warning wiki for detailed descriptions.


Report basic timing measurements on compiler activity.

Defaults to false.

:compiler-stats true


Set the command to install node_modules. Only "npm" and "yarn" supported.

:deps-cmd "yarn"


This flag will cause all (assert x ) calls to be removed during compilation, including implicit asserts associated with :pre and :post conditions. Useful for production. Default is always false even in advanced compilation. Does NOT specify goog.asserts.ENABLE_ASSERTS, which is different and used by the Closure library.

Note that, with JVM ClojureScript, it is not possible to dynamically set *assert* to false at runtime; this compiler flag must explicitly be used to effect the elision. With self-hosted ClojureScript, on the other hand, setting *assert* will cause asserts to be elided as in Clojure.


Whether to elide use strict statements in JavaScript output. Defaults to true.

:elide-strict false


Defaults to false. Whether to enable fingerprinting, which will append a content SHA to output file names. An manifest.edn is generated to :output-dir for mapping fingerprinted file names. This is especially useful when using :modules and :source-map options, as the fingerprinted file names will be appropriately referenced.

:fingerprint true


Requires :static-fns true. This option emits slightly different code that can speed up your code around 10-30%. Higher order function that don’t implement the IFn protocol are normally called with, arg0, arg1 …​). With this option enabled the compiler calls them with a faster f(arg0, arg1 …​ instead.

The :fn-invoke-direct feature is in alpha status. For some libraries such as Reagent, :fn-invoke-direct is known to generate incorrect code.

:fn-invoke-direct true
:elide-asserts true


When using :target :nodejs the compiler will emit a shebang as the first line of the compiled source, making it executable. When your intention is to build a node.js module, instead of executable, use this option to remove the shebang.

:hashbang false


Enables automatically generating externs for interop calls to JavaScript. Defaults to false. For more info see Externs (Alpha)

:infer-externs true

:language-in and :language-out

Configure the input and output languages for the closure library. May be:

  • :ecmascript-next identical to :es-next

  • :ecmascript-2021 identical to :es-2021

  • :ecmascript-2020 identical to :es-2020

  • :ecmascript-2019 identical to :es-2019

  • :ecmascript-2018 identical to :es-2018

  • :ecmascript-2017 identical to :es-2017

  • :ecmascript-2016 identical to :es-2016

  • :ecmascript-2015 identical to :es-2015

  • :ecmascript6 identical to :es6

  • :ecmascript6-strict identical to :es6-strict

  • :ecmascript5 identical to :es5

  • :ecmascript5-strict identical to :es5-strict

  • :ecmascript3 identical to :es3

  • :no-transpile

:language-in defaults to :ecmascript5 :language-out defaults to :no-transpile

:language-in  :ecmascript5
:language-out :no-transpile


Adds dependencies on external js libraries, i.e. Google Closure-compatible javascript files with correct goog.provides() and goog.requires() calls. Note that files in these directories will be watched and a rebuild will occur if they are modified.

Paths or filenames can be given. Relative paths are relative to the current working directory (usually project root).

Defaults to the empty vector []

:libs ["closure/library/third_party/closure"


Flag to disable Node.js runtime support. Useful when not targeting Node.js but rather targeting JavaScript tools which understand Node.js style require conventions

:nodejs-rt false


When set to true, constants, such as keywords and symbols, will only be created once and will be written to a separate file (cljs/core/constants.js). The compiler will emit a reference to the constant as defined in the constants table instead of creating a new object for it. This option is mainly intended to be used for a release build since it can increase performance due to decreased allocation. Defaults to true under :advanced optimizations otherwise to false.

:optimize-constants true


Wrap the Javascript output to avoid clobbering globals. There are four possible value types:

  1. Function - Takes one argument, the compiled javascript output. Should return some other valid javascript output. For the simplest case, just string concatenate the javascript output with something akin to #3 (the default wrapper)

  2. String - Some format interpolation compatible string. For example, "(function(){%s};)()". format receives the compiled javascript output as the second argument and nothing else.

  3. Truthy - Wrap with the default (function(){…​};)()

  4. Falsey - Don’t wrap. This is the default.

;; function
(fn [js-output]
  (str "(function(){" js-output "};).call(window);"))

;; string

;; truthy

;; falsey


Configures which package.json entries (e.g. "browser", "module" or "main") are used in which order when resolving dependencies on (and between) NPM packages.

Defaults to

  • :nodejs (["main"]) if the :target is :nodejs

  • :webpack (["browser", "module", "main"]) else

Can also take a custom vector of entries such as ["browser", "main"].


When set to true, compile source in parallel, utilizing multiple cores.

:parallel-build true


Prepends the contents of the given files to each output file. Files should reside on the classpath. Only valid with optimizations other than :none.

Defaults to the empty vector []

:preamble ["license.js"]

Determines whether comments will be output in the JavaScript that can be used to determine the original source of the compiled code.

Defaults to false.

:print-input-delimiter false


Defaults to

  • false if :target is :nodejs

  • true else

Automatically provide a shim for Node.js process.env containing a single Google Closure define, NODE_ENV with "development" as the default value. In production NODE_ENV will be set to "production". If set to false all of the stated behavior is disabled.


With :advanced mode optimizations, determines whether readable names are emitted. This can be useful when debugging issues in the optimized JavaScript and can aid in finding missing externs. Defaults to false.

:pseudo-names true


For correctness the ClojureScript compiler now always recompiles dependent namespaces when a parent namespace changes. This prevents corrupted builds and swallowed warnings. However this can impact compile times depending on the structure of the application. This option defaults to true.

:recompile-dependents false


Specifies a prefix that will be prepended to all variables. Can be used when Code Splitting to prevent interference with other code in JavaScript’s global scope.

:rename-prefix "prefix"


If set to true, the google closure compiler will add polyfills (for example when you use native javascript Promise). This requires :language-in to be set to :es6 or higher or it will silently be ignored!

:language-in  :es6
:rewrite-polyfills true


Provides fine grained control over the sourceMappingURL comment that is appended to generated JavaScript files when source mapping is enabled.


Set the path to source files references in source maps to avoid further web server configuration.

:source-map-path "public/js"

This option affects the sources entry of the emitted source map V3 JSON file.

:source-map-asset-path ""


Add cache busting timestamps to source map urls. This is helpful for keeping source maps up to date when live reloading code.

:source-map-timestamp true


Whether to disable spec macro checking. Defaults to false.

:spec-skip-macros true


Employs static dispatch to specific function arities in emitted JavaScript, as opposed to making use of the call construct. Defaults to false except under advanced optimizations. Useful to have set to false at REPL development to facilitate function redefinition, and useful to set to true for release for performance.

This setting does not apply to the standard library, which is always compiled with :static-fns implicitly set to true.

:static-fns true

To enable static dispatch for calls to declared functions, supply :arglists meta. For example, if (declare foo) preceeds (foo 1 2), dynamic dispatch will be employed. If instead (declare ^{:arglists '([x y])} foo) preceeds (foo 1 2), static dispatch will be employed if :static-fns is enabled.


Set an arbitrary Clojure function to generate the development main entry point JavaScript file. Must be a symbol representing a Clojure function that exists in a namespace on the classpath. Only used under :optimization :none.

:target-fn '


This flag will turn on/off compiler warnings for references to undeclared vars, wrong function call arities, etc. Can be a boolean for enabling/disabling common warnings, or a map of specific warning keys with associated booleans. Defaults to true.

:warnings true
;; OR
:warnings {:fn-deprecated false} ;; suppress this warning

The following warnings are supported:

  • :declared-arglists-mismatch, declared :arglists mismatch defined

  • :dynamic, dynamic binding of non-dynamic var

  • :extend-type-invalid-method-shape, method arities must be grouped together

  • :extending-base-js-type, JavaScript base type extension

  • :fn-arity, invalid invoke arity

  • :fn-deprecated, deprecated function usage

  • :fn-var, var previously bound to fn changed to different type

  • :infer-warning, warnings related to externs inference

  • :invalid-arithmetic, invalid arithmetic

  • :invalid-array-access, invalid use of aget or aset

  • :invalid-protocol-symbol, invalid protocol symbol

  • :invoke-ctor, type constructor invoked as function

  • :js-shadowed-by-local, name shadowed by a local

  • :multiple-variadic-overloads, multiple variadic arities

  • :munged-namespace, namespace name contains a reserved JavaScript keyword

  • :ns-var-clash, namespace clashes with var

  • :overload-arity, duplicate arities

  • :preamble-missing, missing preamble

  • :private-var-access, private var access from another namespace

  • :protocol-deprecated, deprecated protocol usage

  • :protocol-duped-method, duplicate protocol method implementation

  • :protocol-impl-recur-with-target, target passed in recur to protocol method head

  • :protocol-impl-with-variadic-method, protocol impl employs variadic signature

  • :protocol-invalid-method, protocol method does not match declaration

  • :protocol-multiple-impls, protocol implemented multiple times

  • :protocol-with-overwriting-method, protocol method overwrites other protocol method

  • :protocol-with-variadic-method, protocol declares variadic signature

  • :redef, var redefinition

  • :single-segment-namespace, single segment namespace

  • :variadic-max-arity, arity greater than variadic arity

  • :undeclared-ns, var references non-existent namespace

  • :undeclared-ns-form, namespace reference in ns form that does not exist

  • :undeclared-protocol-symbol, undeclared protocol referred

  • :undeclared-var, undeclared var

  • :unprovided, required namespace not provided

  • :unsupported-js-module-type, unsupported JavaScript module type

  • :unsupported-preprocess-value, unsupported foreign lib preprocess value


Is a function that will be called after a successful build.

Only available for

:watch-fn (fn [] (println "Updated build"))


Set a vector of handlers to customize handling of emitted warnings. A handler should be either a symbol (to be resolved as a function) or a function. The signature of each function is [warn-type env warn-info]. warn-type is a keyword describing the warning, env is the analysis environment, and warn-info is a map of extra useful information for a particular warning type.

Defaults to:

:warning-handlers [cljs.analyzer/default-warning-handler]