# JavaScript Symbols

> Learn how JavaScript Symbol values create unique property keys, how the global symbol registry works, and why symbol properties are not private.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2019-07-26 | Updated: 2026-07-18 | Topics: [JavaScript](https://flaviocopes.com/tags/js/) | Canonical: https://flaviocopes.com/javascript-symbols/

A Symbol is a JavaScript primitive value used as a unique identity. Calling
`Symbol()` creates a new one.

Symbols are mainly used as object property keys. They let libraries add properties without colliding with string keys chosen by other code.

## Create a Symbol

Call `Symbol()`:

```js
const id = Symbol()
```

Do not use `new Symbol()`. Symbol is not a constructor.

Every call creates a different value:

```js
Symbol() === Symbol() //false
```

You can add a description:

```js
const id = Symbol('id')

console.log(id.description) //'id'
console.log(id) //Symbol(id)
```

The description helps with debugging. It does not change the symbol's identity:

```js
Symbol('id') === Symbol('id') //false
```

## Use Symbols as property keys

Use square brackets for a symbol key:

```js
const id = Symbol('id')

const person = {
  name: 'Flavio',
  [id]: 42,
}

console.log(person[id]) //42
```

The Symbol key cannot collide with the string key `'id'`:

```js
person.id = 'public-id'

console.log(person.id) //'public-id'
console.log(person[id]) //42
```

This is useful when different libraries add metadata to the same object.

## Symbol properties are not private

Symbol keys are less visible than string keys, but they are not private or secret.

`Object.keys()` and `Object.getOwnPropertyNames()` skip them:

```js
console.log(Object.keys(person)) //['name', 'id']
```

`for...in` and `JSON.stringify()` skip Symbol-keyed properties too.

But code can still discover them:

```js
console.log(Object.getOwnPropertySymbols(person)) //[Symbol(id)]
console.log(Reflect.ownKeys(person)) //['name', 'id', Symbol(id)]
```

Use private class fields or closures when you need encapsulation. Never use a Symbol to protect sensitive data.

## Share a Symbol with Symbol.for

`Symbol.for()` uses the global symbol registry:

```js
const first = Symbol.for('app.user-id')
const second = Symbol.for('app.user-id')

console.log(first === second) //true
```

This is different from `Symbol()`, which always creates a new value.

Get a registered Symbol's key with `Symbol.keyFor()`:

```js
console.log(Symbol.keyFor(first)) //'app.user-id'
```

`Symbol.keyFor()` returns `undefined` for a Symbol that is not in the registry.

Use a specific, namespaced registry key. A generic key such as `'id'` can collide with unrelated code that uses the same registry.

## Well-known Symbols

JavaScript defines well-known Symbols that let objects participate in language features.

For example, `Symbol.iterator` defines how `for...of` reads values:

```js
const countdown = {
  *[Symbol.iterator]() {
    yield 3
    yield 2
    yield 1
  },
}

console.log([...countdown]) //[3, 2, 1]
```

Other well-known Symbols customize operations such as string matching, type conversion, and `instanceof`.

Most application code does not need to create these protocols. You will see them more often in libraries and built-in objects.

See the MDN references for [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), [`Symbol.for()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for), and [`Object.getOwnPropertySymbols()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols).
