# klona deep cloning modes and limitations

> klona is a small JavaScript deep-cloning utility with four build modes for different data types and property requirements. Its size-focused design is useful, but circular-reference behavior is undocumented.

**lukeed/klona** — A tiny (240B to 501B) and fast utility to "deep clone" Objects, Arrays, Dates, RegExps, and more!

- Repository: https://github.com/lukeed/klona
- Stars: 1,736 · Forks: 51
- Language: JavaScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/lukeed-klona

## Why klona targets size-sensitive JavaScript bundles

klona addresses a narrow but common problem: copying nested JavaScript values without retaining references to nested objects. The README contrasts this with a shallow copy such as `Object.assign`, stating that klona recursively traverses the input and copies values into a new structure. This is useful when application code needs to change part of a nested state tree without changing the original object.

The package is aimed at developers who care about bundle weight and module availability. It publishes CommonJS, ES Module, and UMD forms for each mode, while `package.json` maps those forms to package export paths. The default package entry point uses `dist/index.mjs` for imports and `dist/index.js` for `require`. TypeScript declarations are exposed through `index.d.ts`, and each subpath points to that same declaration file.

The README reports sizes from 240 to 501 bytes when compressed. Those figures describe the package's documented distribution modes, not universal savings in an application bundle. A project can still pay bundler, parser, and transitive dependency costs around the module. The benefit is most direct when klona replaces a larger cloning facility or when an application exposes only the mode that its data actually requires.

## Selecting among klona/json, lite, default, and full

The four package modes are the main adoption decision. They share the `klona(input)` API but progressively add support for types and properties. Selecting the smallest entry point that covers the required data can avoid shipping branches that the application never uses.

The `klona/json` entry point covers JSON data types. The README lists `String`, `Number`, `null`, `Array`, and `Object` for its JSON benchmark category. It is also the smallest documented mode at 240 bytes gzip.

The `klona/lite` entry point adds custom classes, `Date`, and `RegExp` to the JSON-oriented feature set. The README also places `undefined` in the LITE benchmark category. Its documented compressed size is 354 bytes.

The default `klona` entry point adds `Map`, `Set`, `DataView`, `ArrayBuffer`, and `TypedArray`. The default benchmark category includes `RegExp`, `Date`, `Array`, `Map`, `Set`, a custom class, `Int8Array`, `DataView`, and `Buffer`.

The `klona/full` entry point adds `Symbol` properties and non-enumerable properties. The README assigns it 501 bytes gzip. This is the documented choice when symbol-keyed or non-enumerable state must survive cloning. klona does not make every mode interchangeable. Importing `klona/json` gives a smaller implementation, but the README does not claim that this mode copies `Date`, `Map`, or `Set` instances.

## Installing klona and cloning the first nested object

The README gives a single npm installation command. Run it in the JavaScript project that needs the dependency:

```bash
$ npm install --save klona
```

The dollar sign is copied from the README's shell presentation and does not need to be entered when the rest of the command is run. A first ES Module use can import the default build, create a nested input object, and clone it with `klona(input)`:

```js
import { klona } from 'klona';

const input = {
  foo: 1,
  bar: {
    baz: 2,
    bat: { hello: 'world' }
  }
};

const output = klona(input);
output.bar.bat.hola = 'mundo';
output.bar.baz = 99;
```

The package metadata declares Node `>= 8` as its supported engine range. The README does not document a browser compatibility matrix, runtime initialization step, or required environment variable.

If the application handles only JSON data, the import path can be narrowed without changing the function call:

```js
import { klona } from 'klona/json';
```

The README does not provide a second complete usage example for this import. The behavior to verify is that `klona(input)` returns a deep copy whose nested properties can be changed without changing the source.

## The recursive copy contract and undocumented edges

The public contract is intentionally small. `klona(input)` returns a deep copy of the input, and the type declaration metadata points consumers to `index.d.ts`. The README describes independence at the value level. Its example changes nested properties on the returned object and leaves the original nested values unchanged.

That contract has boundaries that readers should not fill in by assumption. The README does not document circular references, shared-reference identity, functions, promises, errors, weak collections, property descriptors, or prototype preservation beyond its stated custom-class support. It also does not define how a repeated object reference should be handled. If two properties point to the same object, recursive cloning might create separate clones or preserve sharing, but the documentation does not establish the result.

Cyclic input is especially important because a recursive traversal would need explicit cycle detection. The README does not state whether klona detects a cycle, throws an error, overflows, or follows another policy. An application that stores parent references, linked records, or cyclic graphs should not assume support from the phrase "deep clone."

The distinction between enumerable, symbol, and non-enumerable properties is documented through separate modes. That is useful, but it also means ordinary development fixtures may conceal mode-selection mistakes. The repository does not document a debug flag or mode detector that identifies an incorrect import before runtime. Use the exact mode that matches the production data contract.

## Published klona benchmark context and the clone alternative

The README includes a benchmark table and states that the results were produced with Node v12.18.3. Those values describe the project's published test context and should not be treated as current results for every runtime, input shape, or build pipeline. The README also notes that candidates had to pass validation, which matters because speed without equivalent output is not a useful comparison.

Within the documented DEFAULT category, klona is listed at 230,257 ops/sec, while `clone` is listed at 92,127 ops/sec. The table marks `clone` as failing the `DataView` validation check. klona/full is the only listed candidate in the FULL benchmark category at 82,346 ops/sec, while `clone/include` is marked as failing `DataView` validation and producing incorrect non-enumerable properties.

This makes `clone` a concrete alternative, not merely a named competitor. Its documented default path does not pass the `DataView` case in this benchmark, while klona's default mode is documented to support `DataView`. The alternative's `include` option adds non-enumerable handling but does not fix every full-mode discrepancy reported by the table. Conversely, choosing klona for those cases does not establish compatibility with cyclic graphs or every runtime behavior.

The benchmark directory is included in the repository and separates JSON, LITE, DEFAULT, and FULL cases. The README does not document a single command for reproducing the complete table, so the published figures should remain attributed to the README rather than presented as independently confirmed measurements.

## Maintenance signals, license, and klona upgrade work

The repository is not archived, and its last push was on 2026-04-10. That is a current maintenance signal. Release history is less frequent: the recent releases are `v2.0.6` on 2023-01-16, `v2.0.5` on 2021-10-27, and `v2.0.4` on 2020-09-16. The gap between the last push and the latest listed release means repository activity should not be described as a steady sequence of package releases.

`package.json` declares Node `>= 8`, CommonJS and ES Module distributions, and a build script that uses `bundt`. The declared build command is:

```bash
npm run build
```

The project also defines a `test` script in `package.json` that invokes `uvu -r esm test -i suites`.

Before upgrading an existing application, compare the currently locked release with the release selected by the package manager. The README does not provide an upgrade guide, and its benchmark uses Node v12.18.3. Compatibility testing should therefore focus on the selected export path and the exact data categories that the application clones.

The package uses the MIT license. The repository includes a `license` file, and `package.json` declares `"license": "MIT"`. That identifies the published license, but it is not legal advice. Organizations with separate license-review or notice-retention policies still need to inspect the repository license text and their own dependency process.

## Conclusion

klona is a reasonable choice for small JavaScript codebases that need a recursively copied subset of ordinary data types and a low package footprint. It is a poor fit when the application requires documented circular-reference support, broad compatibility with specialized objects, or a current performance comparison. Before adoption, first reproduce the production object graph with the selected `klona/json`, `klona/lite`, `klona`, or `klona/full` entry point, then inspect whether symbol keys, non-enumerable properties, custom classes, and binary containers occur in real data.

## FAQ

### How do I install klona and import its default deep-clone function?

Run `npm install --save klona`, then import the named function with `import { klona } from 'klona';`. The package metadata supports both ES Module imports and CommonJS `require`.

### Which klona mode should I use for Map, Set, and typed arrays?

Use the default `klona` import. The README says this mode extends `klona/lite` with `Map`, `Set`, `DataView`, `ArrayBuffer`, and `TypedArray`; use `klona/full` when symbol or non-enumerable properties are also required.

### Does klona handle circular object references?

The README does not document circular-reference handling, shared-reference identity, or the expected failure behavior for cyclic input. Verify those cases against the selected klona mode before using it for cyclic application state.

### Does the klona benchmark reflect current JavaScript performance?

The published benchmark uses Node v12.18.3. Its figures apply to the README's documented cases and environment, but the repository does not supply newer measurements across current runtimes.

## Sources

- [Issues](https://github.com/lukeed/klona/issues)
- [License: MIT](https://github.com/lukeed/klona/blob/master/LICENSE)
- [lukeed/klona on GitHub](https://github.com/lukeed/klona)
- [README](https://github.com/lukeed/klona/blob/master/README.md)
- [Releases](https://github.com/lukeed/klona/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lukeed-klona
