mrkeyoor.com_
Wed 23 Sept 00:33 UTC
npmUtilsupdated 22 Sept 2026

scuid review

scuid 1.1.0 creates cuid-shaped identifiers from a prefix, base-36 timestamp, counter, process fingerprint, and two Math.random blocks. The normal result is 25 characters; slug() returns a shorter variable-width form. create() can change the prefix, radix, block length, hostname, or random source. Our package inspection found one 28 KB CommonJS module with no dependencies or types. The npm metadata still points to a GitHub repository that returns 404, so the published tarball is the only code available to audit. These values aim to avoid collisions, not resist guessing.

Verdict

scuid 1.1.0 installed as one 1 MB package in 0.5 seconds, but our browser build failed, no types were present, and its default host fingerprint is constant because of a source bug. Keep it only for cuid-format compatibility with an explicit hostname; install cuid2, nanoid, ULID, or UUID for new IDs.

We installed it

Lab card: what happened when we installed scuidScreenshot of scuid documentation
Install✓ · 0.5s1 package on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does scuid install cleanly?

Yes. In a fresh container with an empty cache, npm install scuid finished in 0.5s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

Can scuid run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does scuid work with both ESM and CommonJS?

Yes. Both import 'scuid' and require('scuid') worked in Node 22 in our run. The package is published as CommonJS.

Does scuid include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

scuid or @paralleldrive/cuid2: which should you use?

@paralleldrive/cuid2: Use it for the successor recommended by deprecated cuid, with cryptographic randomness and no exposed timestamp prefix. scuid 1.1.0 installed as one 1 MB package in 0.5 seconds, but our browser build failed, no types were present, and its default host fingerprint is constant because of a source bug.

When should you not use scuid?

The identifier protects a secret or access path. Math.random plus exposed time, counter, and fingerprint components makes output predictable enough to reject for tokens.

API stability4/5npm shows only three published versions and no release after 1.1.0 on February 4, 2018. The callable export, slug(), fingerprint helpers, create(), and constructor property have therefore stayed unchanged for years, as has the stored ID format. That practical stability comes from abandonment. Correcting the hostname default would alter fingerprints, and there is no active repository where a compatibility policy is discussed.
Docs2/5The README demonstrates the default generator, slug(), fingerprint(), and create() options, and the unpkg copy returned HTTP 200. It is also the only surviving reference because the linked repository is gone. Its sample implies a fixed 7-character slug even though output can reach 10, and the hostname option description does not reveal that the default stores an uncalled function. Test and benchmark commands point to files absent from the tarball.
Maintenance1/5Version 1.1.0 was published on February 4, 2018. The jhermsmeier/node-scuid URL recorded by npm returns 404, so there is no visible issue tracker, commit history, release pipeline, or source test suite. A defect found in the installed hostname default has no public reporting or repair path. npm has not applied a deprecation flag; the available development evidence still supports treating it as abandoned.
Ecosystem2/5npm counted 4,217,407 downloads for August 18 through 24, 2026, showing that old dependency graphs still carry scuid. Our inspection found no types, ESM build, browser bundle, peers, or framework adapters. Its useful compatibility is limited to the original cuid-shaped string. That package is now deprecated and points users to cuid2, whose format and security design are intentionally different.

Use it if

  • Existing records and APIs already require the original cuid string layout.
  • A timestamp prefix should make later full identifiers generally sort after earlier ones as strings.
  • A legacy caller needs create({ rng }) to inject an object with a random() method.
  • You are preserving a transitive dependency and can audit the complete 28 KB published package yourself.
Skip it if

Setup reality

We installed scuid 1.1.0 in 0.5 seconds in a fresh Node 22 Bookworm container. It left 1 package and 1 MB on disk, and npm audit found 0 known vulnerabilities. The package has no direct or peer dependencies, is 28 KB unpacked, and uses the MIT license. It is CommonJS without an exports map. require() and ESM import both succeeded in our checks, but no TypeScript declarations were found. An esbuild browser bundle failed, which matches its dependency on Node process and OS details.

There are no credentials, native builds, or config files. The published artifact contains package metadata, a license, a README, and lib/scuid.js. Its linked repository returns 404, so production review has to start with that installed source. The default export is a shared generator; create() returns a configured instance, and the class itself is exposed under the unusual constructor property.

The most important default is faulty. hostname is assigned the os.hostname function rather than os.hostname(). Fingerprint code then reads that function's zero argument length and generates the same trailing 10 host block everywhere. Pass create({ hostname: os.hostname() }) if compatibility forces you to keep scuid, although that changes the fingerprint portion compared with the broken default.

Full IDs are 25 characters, while slug output ranges from 7 to 10 as the counter grows. The counter wraps after 36^4 values, and the random blocks use Math.random. Do not use either form as an API key, reset token, invitation secret, or proof of authorization. For new database identifiers, choose cuid2, nanoid, ULID, or UUID according to whether randomness, ordering, or a standard format matters.

Patterns

Create one full identifier generate-an-id

const scuid = require('scuid')

const id = scuid()
console.log(id)          // 'cmskv45910000ef10v34xxchc'
console.log(id.length)   // 25

Output is 25 characters: `c`, 8 timestamp characters, 4 counter characters, a 4-character fingerprint, and two random blocks of 4.

Correct the default hostname input fix-the-fingerprint

const os = require('node:os')
const scuid = require('scuid')

console.log(scuid.fingerprint())                        // 'ef10' - host block is always '10'

const generator = scuid.create({ hostname: os.hostname() })
console.log(generator.fingerprint())                    // 'efjx' - host block now varies

Version 1.1.0 stores the os.hostname function itself, producing a constant host block. Calling os.hostname() before create() supplies the intended string.

Generate the shorter slug form generate-a-slug

const scuid = require('scuid')

const slugs = Array.from({ length: 5 }, () => scuid.slug())
console.log(slugs)
console.log(new Set(slugs.map((s) => s.length)))  // widths vary

Slug width grows from 7 through 10 characters with the counter. Database and API validation must allow that range.

Inject a random-number provider custom-rng

const crypto = require('node:crypto')
const scuid = require('scuid')

const secure = scuid.create({
  rng: { random: () => crypto.randomInt(0, 2 ** 30) / 2 ** 30 },
})

console.log(secure.id())

A custom RNG changes two blocks only. Time, counter, and fingerprint data remain exposed, so the complete value is unsuitable as a secret.

Configure a separate generator configured-instance

const os = require('node:os')
const scuid = require('scuid')

const ids = scuid.create({
  prefix: 'u',
  hostname: os.hostname(),
  pid: process.pid,
})

console.log(ids.id(), ids.slug(), ids.fingerprint())

The README warns that base, blockSize, and fill changes break cuid compatibility. Prefix and hostname can change without altering field widths.

Sort identifiers by their prefix sort-by-creation

const scuid = require('scuid')

const rows = [scuid(), scuid(), scuid()].map((id) => ({ id }))
rows.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
// string sort matches creation order within one process

Ordering depends on system clocks. Multiple machines can interleave values, and a backward clock correction can reverse expected creation order.

Validate the full string shape validate-format

const ID_RE = /^c[0-9a-z]{24}$/

function isScuid (value) {
  return typeof value === 'string' && ID_RE.test(value)
}

scuid provides no parser or validator. A regular expression can confirm syntax but cannot prove that your application issued the value.

Account for counter rollover counter-wraps

const scuid = require('scuid')
const instance = scuid.create({})

console.log(instance.discreteValues)  // 1679616  = 36 ** 4
// the counter cycles through that range, then restarts at 0

The counter range is 36^4. After it wraps within the same timestamp, collision resistance rests on the two Math.random blocks.

Inspect an explicit fingerprint per-process-fingerprint

const scuid = require('scuid')

console.log(scuid.fingerprint())
console.log(scuid.createFingerprint(process.pid, require('node:os').hostname()))

createFingerprint() with a hostname string varies by host. The singleton fingerprint does not because its default contains the uncalled function.

Review the installed implementation read-the-source

npm pack scuid
tar tzf scuid-1.1.0.tgz
# package/package.json
# package/LICENSE.md
# package/README.md
# package/lib/scuid.js

The npm artifact is the available source of record because its repository link returns 404. Inspect lib/scuid.js from the installed 28 KB package.

Reject scuid for secret values avoid-for-secrets

const crypto = require('node:crypto')

// wrong: predictable timestamp, counter and fingerprint
// const resetToken = require('scuid')()

const resetToken = crypto.randomBytes(32).toString('base64url')

Upstream cuid's npm notice calls its sortable design insecure and recommends cuid2. scuid repeats the predictable components that motivate that warning.

Introduce cuid2 for new rows migrate-to-cuid2

const { createId, isCuid } = require('@paralleldrive/cuid2')

const id = createId()
console.log(isCuid(id))

// keep scuid only for reading rows that already exist
// const legacy = require('scuid')

cuid2 uses a different string format, so migrations must accept old and new identifiers together. It also drops time sorting to avoid a predictable prefix.

Alternatives

PackageRegistryPick it when
@paralleldrive/cuid2npmUse it for the successor recommended by deprecated cuid, with cryptographic randomness and no exposed timestamp prefix.
nanoidnpmUse it for short URL-safe random IDs when creation-time ordering is unnecessary.
ulidnpmUse it for a documented sortable format with a millisecond timestamp that can be decoded.
uuidnpmUse it when interoperability matters, including UUIDv7 for time-ordered database keys.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.