These two options decide which JavaScript your protected file is written in. They are not protection levels: everything you enabled still runs, and the same code is still obfuscated. They only choose the syntax it comes out as.
TargetVersion
es5 (default) — ES2015+ syntax is down-levelled, so classes, arrow functions, destructuring, template literals and for-of become code a pre-ES2015 engine can run.
modern — the down-levelling pass is skipped and the output keeps the syntax your source used. Choose this when the file is served to current browsers or run on Node.js.
If you already build with Babel, TypeScript or a bundler target, the decision is made there: set this to match what your build emits, and the protected file will not reintroduce syntax your toolchain deliberately removed.
Syntax that still needs a modern runtime
The ES5 target lowers supported syntax; it is not a complete JavaScript transpiler. Async functions, generators, private class members, static initialization blocks, BigInt, newer regular expressions, and new.target retain their native syntax. Classes with private members and their subclasses also stay native. This includes bases returned by factories or mixins when the engine cannot safely lower the inheritance chain. Object methods and accessors that use super, including computed method names, retain their native syntax to preserve their home object.
TransformObjectKeys requires TargetVersion=modern: it introduces computed property keys after the lowering pass. Public protection entry points reject that option with the ES5 target. Test the protected file in the oldest runtime you support.
DownlevelIteration
On the es5 target, lazy iteration is enabled by default. Generators advance as the loop runs, and iterator cleanup runs when the loop exits early. This avoids draining a generator before the loop body executes.
Explicit DownlevelIteration=False retains legacy eager lowering and produces a warning. It may reduce overhead for ordinary array loops, but can change generator side effects and cleanup. Measure your protected application before choosing this compatibility opt-out.
On modern this option changes nothing: native for-of is kept. The ES5 compatibility fallback accepts array-like values without an iterator; this is not a claim of full ECMAScript iterator conformance.
Setting it
Online tool. Two options in the feature list, badged Output: Modern Output (ES2015+) and Spec-Faithful for-of (ES5). Modern Output is off by default. Lazy ES5 iteration is enabled by default and shown as a fixed safety setting in the online tool; legacy eager iteration requires an explicit API opt-out.
npm package (jso-protector 0.4.0+), in jso.config.json:
{
"preset": "balanced",
"targetVersion": "modern"
}
or on the command line:
jso-protector --option TargetVersion=modern
jso-protector --option DownlevelIteration=True
API requests carry the option by name: set TargetVersion and DownlevelIteration alongside your other options. See npm options for the full option surface.
The desktop app does not expose these two in its options dialog yet. Until it does, protect with the npm package or the API when you need a target other than the es5 default.
What to check after switching
- Moving to
modern: confirm the oldest engine you support really does handle ES2015+. The protected file will contain the same syntax family your source did.
- Staying on
es5: keep the default lazy iteration, and test generator side effects, early exits, cleanup, and hot-loop performance.
- Either way: run your own test suite against the protected build. That is the check that catches everything, and it is the one we recommend regardless of options.
Frequently asked questions
Does the output target change how strongly my code is protected?
No. TargetVersion and DownlevelIteration choose which JavaScript the protected file is written in; every protection option you enabled runs either way. That is why the online tool badges them Output rather than listing them among the protection toggles, independently of protection presets.
Which target should I use?
Use modern when the file is served to current browsers or run on Node.js, which is the common case for an app that already ships through a bundler. Use es5, the default, when the protected file has to run on a pre-ES2015 engine, such as an embedded WebView or an old kiosk browser. If you already run Babel or TypeScript, they have decided this for you, and the protected file only needs to match what they emit.
What does DownlevelIteration change?
On the es5 target it makes for-of lowering spec-faithful: the iterable is stepped lazily and the iterator’s return hook runs on break, throw, and early return. Lazy iteration is enabled by default; explicit DownlevelIteration=False retains legacy eager iteration with a warning. It has no effect when TargetVersion is modern, because a modern target keeps native for-of.
When does the difference actually matter?
When you iterate something that is not an array and stopping early matters: a generator, a stream reader, or any iterator with side effects per step. Ordinary arrays may incur additional per-step overhead; measure your protected application.
Where can I set the output target?
In the online tool as the Modern Output and Spec-Faithful for-of options, in jso-protector 0.4.0 or later as targetVersion and downlevelIteration in jso.config.json, and in API requests as TargetVersion and DownlevelIteration. The desktop app does not expose them in its options dialog yet.