npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

sort-keys

v6.0.0

Published

Sort the keys of an object

Readme

sort-keys

Sort the keys of an object

Useful to get a deterministically ordered object, as the order of keys can vary between engines.

Install

npm install sort-keys

Usage

import sortKeys from 'sort-keys';

sortKeys({c: 0, a: 0, b: 0});
//=> {a: 0, b: 0, c: 0}

sortKeys({b: {b: 0, a: 0}, a: 0}, {deep: true});
//=> {a: 0, b: {a: 0, b: 0}}

sortKeys({b: [{b: 0, a: 0}], a: 0}, {deep: true});
//=> {a: 0, b: [{a: 0, b: 0}]}

sortKeys({c: 0, a: 0, b: 0}, {
	compare: (a, b) => -a.localeCompare(b)
});
//=> {c: 0, b: 0, a: 0}

sortKeys([{b: 0, a: 2}], {deep: true});
//=> [{a: 2, b: 0}]

Advanced Usage with context

The deep and ignoreKeys options can receive a context object with detailed information about the current key being processed:

// Ignore private keys only at root level
sortKeys(data, {
	ignoreKeys: ({key, depth}) => key.startsWith('_') && depth === 0
});

// Deep process only up to 3 levels, skip config paths
sortKeys(data, {
	deep: ({path, depth}) => depth < 3 && !path.includes('config')
});

// Complex path-based logic
sortKeys(data, {
	deep: ({path}) => !(path[0] === 'user' && path[1] === 'cache'),
	ignoreKeys: ({path, key}) => (path.length === 1 && path[0] === 'metadata') || key.startsWith('_')
});

API

sortKeys(object, options?)

Returns a new object with sorted keys.

Property descriptors are preserved, including accessors (get/set), and getters are not invoked or deep-processed. Circular references are supported and preserved.

object

Type: object | Array

When it's an object:

  • Only plain objects are deeply processed.
  • Only enumerable own string keys are considered; symbol and non-enumerable properties are ignored.

When it's an array:

  • Array order is unchanged; holes in sparse arrays are preserved.
  • Elements may be deep-processed if deep enables it.
  • Extra enumerable properties on arrays are ignored.

options

Type: object

compare

Type: Function

Compare function for sorting keys.

If omitted, remaining keys are sorted using the platform's default string sort.

sortKeys(object, {
	compare: (a, b) => b.localeCompare(a) // Reverse alphabetical
});
deep

Type: boolean | Function
Default: false

Recursively sort keys, including keys of objects inside arrays.

Only plain objects are sorted; other object types are left as-is. For arrays, deep processing applies to their elements.

When a boolean:

  • true: Deep process all nested objects and arrays.
  • false: Only sort keys at the current level.

When a function, it receives a context object and should return true to enable deep processing for that specific key-value pair:

sortKeys(data, {
	deep: ({key, value, path, depth}) => {
		// Only deep process up to 2 levels
		if (depth >= 2) {
			return false;
		}

		// Skip deep processing of large arrays for performance
		if (Array.isArray(value) && value.length > 100) {
			return false;
		}

		// Skip config objects entirely
		if (path.includes('config')) {
			return false;
		}

		return true;
	}
});
ignoreKeys

Type: string[] | Function
Default: []

Keys to ignore when sorting. Ignored keys will appear first in their original order, followed by the sorted keys. Remaining keys are sorted by compare, or by default string sort if compare is not provided.

Can be an array of key names:

sortKeys({c: 0, _private: 1, a: 0, b: 0}, {ignoreKeys: ['_private']});
//=> {_private: 1, a: 0, b: 0, c: 0}

Or a function that receives a context object:

sortKeys(data, {
	ignoreKeys: ({key, value, path, depth}) => {
		// Ignore private keys at root level
		if (key.startsWith('_') && depth === 0) {
			return true;
		}

		// Ignore metadata keys in user objects
		if (path[0] === 'user' && key === 'metadata') {
			return true;
		}

		// Ignore empty objects
		if (typeof value === 'object' && Object.keys(value).length === 0) {
			return true;
		}

		return false;
	}
});

Note: ignoreKeys only affects the ordering of object keys; it does not control deep processing, and array indices are not sorted or filtered. To prevent deep processing of specific values, use the deep function option.

Context object

When using functions for deep or ignoreKeys, they receive a context object with:

  • key (string): The current key being processed.
  • value (any): The value associated with the current key.
  • path (string[]): The full path to this key as an array of elements (for example, ['user', 'profile', 'name']). Array indices are stringified (for example, ['items', '0', 'title']).
  • depth (number): The current nesting depth (0 for root level).

Path examples

const data = {
	user: {
		profile: {
			name: 'John'
		}
	},
	items: [
		{title: 'Item 1'},
		{title: 'Item 2'}
	]
};

// Paths generated during processing (as arrays):
// ['user'] (depth: 0)
// ['user', 'profile'] (depth: 1)
// ['user', 'profile', 'name'] (depth: 2)
// ['items'] (depth: 0)
// ['items', '0'] (depth: 1)
// ['items', '0', 'title'] (depth: 2)
// ['items', '1'] (depth: 1)
// ['items', '1', 'title'] (depth: 2)

Note: path is an array of elements with stringified array indices (for example, ['items', '0', 'title']). If your key names include dots or special characters, this representation remains unambiguous.