# devtools.nicxon.tech — full corpus for LLM ingestion > Every developer tool on devtools.nicxon.tech, in one file. Each section is a single > tool: its purpose, how to use it, a worked example, the gotchas, and answers to the > four most common failure modes. All processing happens in your browser; nothing is > uploaded. The canonical HTML page for each tool is at > https://devtools.nicxon.tech/tools//. --- # Base64 encoder & decoder > Encode UTF-8 text or any file to Base64 (standard or URL-safe), and decode a Base64 string back to text or a downloadable file. Runs in your browser; no upload. ## What this does Base64 maps arbitrary bytes onto 64 printable ASCII characters so binary data can pass through systems that only handle text. This tool encodes UTF-8 text or any file you select, and decodes a Base64 string back to text — or, when the bytes aren't valid text, to a downloadable file. It supports both the standard alphabet and the URL-safe variant, and it tolerates missing padding and embedded whitespace on decode. File encoding happens with the `File` and `FileReader` APIs in your browser. The bytes are never uploaded, so encoding a certificate, a private key, or a document to embed in a config file is safe to do here. ## When you'd use it - Embedding a small image or font in a CSS `data:` URI or an HTML page. - Putting a binary file into a JSON or YAML field that only accepts strings. - Decoding the `Authorization: Basic` header value to see the username and password it carries. - Inspecting the payload of a Base64URL token by hand. - Preparing a Kubernetes `Secret`, whose values are Base64-encoded. ## Worked example Encode the text `user:pa55` with the standard alphabet: ``` dXNlcjpwYTU1 ``` That is exactly what sits after `Basic ` in an HTTP `Authorization` header. Switch Mode to Decode, paste `dXNlcjpwYTU1`, and you get `user:pa55` back — demonstrating that Basic auth offers no confidentiality without HTTPS. Now tick *URL-safe* and encode the bytes `0xFB 0xFF` (paste them as text won't work; use a 2-byte file). Standard Base64 gives `+/8=`; URL-safe gives `-_8` — same bytes, different characters, no padding. ## Limits and gotchas - **Not a cipher.** Base64 provides zero secrecy. Encode-then-encrypt, never encode-instead-of-encrypt. - **Text mode assumes UTF-8.** Pasting text in another encoding and encoding it will produce UTF-8 bytes, which may not match what another system expects. - **Whitespace on decode is ignored,** which is lenient. A stricter decoder elsewhere may reject the same input if it contains newlines. - **Large files** are held entirely in memory as a string during encoding; multi-hundred-megabyte files can exhaust the tab. - **MIME line wrapping** (76-character lines) is not added. If a legacy system needs wrapped output, wrap it after copying. ## How to use - **Pick encode or decode** — Set Mode to Encode to produce Base64, or Decode to read Base64 back. - **Provide input** — Type or paste text into the box, or choose a file to encode. Files are read locally. - **Choose the alphabet** — Leave standard Base64 for most uses, or tick URL-safe for tokens that travel in a URL or filename. - **Read the output** — Copy the encoded string, or for a decoded binary result use the download button. ## Frequently asked questions ### What is the difference between Base64 and Base64URL? Standard Base64 uses +, /, and = padding. Those three characters have special meaning in URLs and filenames, so Base64URL replaces + with -, / with _, and usually drops the = padding. The decoded bytes are identical; only the text representation differs. JWTs use Base64URL. ### Why did decoding produce garbled characters? The Base64 decoded fine, but the resulting bytes are not UTF-8 text — they might be an image, a gzip stream, or text in another encoding. This tool detects that and offers a download instead. Garbled output specifically means the bytes were forced through a UTF-8 decoder that couldn’t make sense of them. ### Is Base64 encryption? Is it safe to put a password in it? No. Base64 is a reversible encoding with no key. Anyone can decode it instantly. It exists to carry binary data through text-only channels (email, JSON, URLs), not to protect anything. Never treat a Base64 string as a secret in itself. ### The encoded output is bigger than my input — is that expected? Yes. Base64 represents every 3 bytes as 4 ASCII characters, so output is about 33% larger than input, plus padding and any line breaks. This is the cost of using only printable characters. --- *Source: [https://devtools.nicxon.tech/tools/base64/](https://devtools.nicxon.tech/tools/base64/) — generated by devtools.nicxon.tech.* --- # Cron expression builder > Build a cron expression from fields, read it back in plain English, and preview the next five run times. ## What this does A cron expression is five space-separated fields — minute (0–59), hour (0–23), day of month (1–31), month (1–12), day of week (0–7, where 0 and 7 are both Sunday) — each of which can be a number, a list (`1,15`), a range (`9-17`), a step (`*/15`), or `*`. This tool renders the expression as an English sentence using [cronstrue](https://github.com/bradymholt/cRonstrue) and computes the next five fire times with [cron-parser](https://github.com/harrisiirak/cron-parser) in the time zone you select. It's a static page with the logic bundled in — no request is made when you type. ## When you'd use it - Writing a schedule for a cron job, a CI pipeline, a serverless function, or a Kubernetes CronJob and wanting to confirm it means what you think. - Reading an unfamiliar cron line in someone else's config. - Checking when a job will next run, and whether a change shifts that. - Debugging a job that "didn't run" — often a day-of-week vs day-of-month interaction or a step value that doesn't divide evenly. ## Worked example The default expression: ``` */15 9-17 * * 1-5 ``` reads as "every 15 minutes, between 09:00 and 17:59, Monday through Friday". Note it fires at 17:00, 17:15, 17:30, and 17:45 but not 18:00, because the hour range `9-17` includes hour 17 in full. If you wanted it to stop at 17:00 exactly, the expression is `0,15,30,45 9-16 * * 1-5` plus a separate `0 17 * * 1-5`, or simply `*/15 9-17 * * 1-5` accepted as "through the 5 o'clock hour". Change the last field to `1-5` → `6,0` and the next-runs list jumps to Saturday and Sunday. ## Limits and gotchas - **5 fields only.** No seconds field, no `@daily`-style macros, no `L`/`W`/`#` Quartz extensions. - **OR semantics for the two day fields.** Restricting both day-of-month and day-of-week broadens the schedule rather than narrowing it. - **Steps start from the minimum.** `*/40` in minutes is 0 and 40 only, then it resets at the top of the hour. - **DST.** Run times near a daylight-saving change can be skipped or doubled depending on the running system's rules. - **The runner's clock wins.** This tool's prediction assumes the schedule is interpreted in the zone you pick; verify what your platform actually uses. ## How to use - **Type an expression or use the fields** — Enter a 5-field cron expression directly, or edit the per-field boxes and the expression updates. - **Pick a time zone** — Choose the zone the schedule should run in. The next-run times are shown in that zone and in UTC. - **Read the plain\-English description** — Confirm the sentence matches what you intended before you deploy the schedule. - **Check the next 5 runs** — Verify the upcoming run times look right — this catches most off-by-one and day-of-week mistakes. ## Frequently asked questions ### Why does my "day of month" and "day of week" both being set behave oddly? In standard cron, when both field 3 (day of month) and field 5 (day of week) are restricted (neither is *), the job runs when either matches, not both. So 0 0 13 * 5 means "midnight on the 13th, and also every Friday", not "Friday the 13th". To get a single condition, leave the other field as *. ### What does */15 actually mean? A step value. */15 in the minute field means minutes 0, 15, 30, 45. It is "every 15 starting from the field's minimum", not "15 minutes after whenever the job last ran". */20 in the hour field gives 0 and 20 — because there is no hour 40 — which is a common surprise. ### Is the schedule in UTC or my local time? That depends on the system running it. Linux cron uses the machine's local time zone; many managed schedulers default to UTC. This tool lets you pick, and shows each run in both the chosen zone and UTC so you can match it to your platform. Around daylight-saving transitions, a job scheduled for a skipped or repeated local hour may run zero or two times. ### Does this support seconds or the @hourly / @daily shortcuts? No. This tool handles the classic 5-field format (minute, hour, day-of-month, month, day-of-week). Six-field expressions with a leading seconds field (used by Quartz, some Kubernetes tooling, and node-cron) and named shortcuts like @daily are not parsed here. --- *Source: [https://devtools.nicxon.tech/tools/cron/](https://devtools.nicxon.tech/tools/cron/) — generated by devtools.nicxon.tech.* --- # CSV ↔ JSON converter > Turn CSV into an array of objects and back, with delimiter and header control. ## What this does CSV → JSON reads delimited text and produces either an array of objects (when the first row is a header) or an array of arrays (when it isn't). JSON → CSV takes an array and writes one row per element, with a header row derived from the union of all object keys. Parsing and serialization are handled by [PapaParse](https://www.papaparse.com/), which implements RFC 4180 quoting rules and handles quoted newlines, escaped quotes, and ragged rows. Everything runs in your browser, so a customer export, a finance report, or a user list can be reshaped here without uploading it anywhere. ## When you'd use it - Turning a spreadsheet export into JSON to seed a database or a test fixture. - Converting an API's JSON array into CSV to open in a spreadsheet or hand to a non-technical colleague. - Inspecting exactly how a CSV parses — where the column breaks land, what types are inferred — before writing code against it. - Changing the delimiter of a file (for example semicolon-separated European CSV to comma-separated). ## Worked example Input CSV, with "First row is header" and "Infer numbers & booleans" both on: ``` sku,name,price,in_stock A-100,Widget,9.99,true A-101,Gadget,14.5,false ``` Output JSON: ``` [ { "sku": "A-100", "name": "Widget", "price": 9.99, "in_stock": true }, { "sku": "A-101", "name": "Gadget", "price": 14.5, "in_stock": false } ] ``` Note that `sku` stays a string because it isn't numeric, while `price` becomes a number and `in_stock` becomes a boolean. Convert that JSON back with direction JSON → CSV and you get the original file, with a ` ` after each row. ## Limits and gotchas - **Type inference is heuristic.** It's convenient but lossy — turn it off whenever the exact text of a field matters. - **Nested data doesn't survive JSON → CSV.** Flatten objects and arrays into scalar columns first. - **Inconsistent columns.** If some rows have more fields than the header, the extras land under numeric keys; if fewer, missing keys are empty strings. - **Big files.** Parsing is done in one pass in memory. Multi-hundred-megabyte files may exhaust the tab's memory. - **Excel quirks.** A leading `=` in a cell is data here, not a formula; a UTF-8 BOM at the start of the file is stripped on parse. ## How to use - **Choose a direction** — CSV → JSON to parse a spreadsheet export, or JSON → CSV to flatten an array of records. - **Set the delimiter** — Leave it on Auto for most files, or pick comma, semicolon, tab, or pipe if auto-detection guesses wrong. - **Set header and typing options** — For CSV → JSON, decide whether the first row is a header and whether numbers and booleans should be inferred. - **Read and copy** — The converted output appears on the right with a row count and the detected delimiter. Copy it out. ## Frequently asked questions ### Why are my leading zeros gone (007 became 7)? That happens when "Infer numbers & booleans" is on: 007 is read as the number 7. Zip codes, product codes, and phone numbers should stay text — turn that option off, or the value will lose its formatting. With inference off, every field is kept as a string. ### My file has commas inside quoted fields and the columns are misaligned. A properly quoted CSV ("Smith, John",42) parses correctly here. Misalignment usually means the quoting is inconsistent — an unescaped quote inside a field, or a mix of quoted and unquoted rows. The error message names the row number; check that row for a stray ". ### JSON → CSV produced [object Object] in a cell. CSV is flat: one value per cell. If a record contains a nested object or array, there is no correct way to put it in a single cell, so it is stringified. Flatten nested fields first (for example address.city as its own column) before converting. ### Which line endings and encoding does the output use? Output CSV uses \r\n line endings, which is what the CSV specification (RFC 4180) and Excel expect. Text is UTF-8. If a downstream tool needs \n only, convert the line endings after copying. --- *Source: [https://devtools.nicxon.tech/tools/csv-json/](https://devtools.nicxon.tech/tools/csv-json/) — generated by devtools.nicxon.tech.* --- # Hash generator > Compute MD5, SHA-1, SHA-256, and SHA-512 digests of text or a file, with hex and Base64 output. ## What this does A cryptographic hash turns any input into a fixed-size digest. The same input always produces the same digest; changing a single bit changes about half the output bits. This tool computes four digests at once — MD5 (128 bit), SHA-1 (160 bit), SHA-256, and SHA-512 — over UTF-8 text or the raw bytes of a file. SHA functions use the browser's [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) implementation; MD5 uses a bundled library because SubtleCrypto doesn't provide it. Files are read locally with the `File` API and never uploaded, so you can fingerprint a private document or a build artifact without it leaving your machine. ## When you'd use it - Verifying that a downloaded ISO, binary, or archive matches the checksum the publisher listed. - Confirming two files are byte-for-byte identical without diffing them. - Generating an `ETag`-style fingerprint or a cache key for a piece of content. - Reproducing a hash that another tool or language produced, to debug a mismatch. - Checking a value against a legacy system that still stores MD5 or SHA-1 digests. ## Worked example Hash the text `hello` (no newline), lowercase hex: ``` MD5 5d41402abc4b2a76b9719d911017c592 SHA-1 aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d SHA-256 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 SHA-512 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 ``` Run `printf 'hello' | sha256sum` on any Linux box and you get the same SHA-256 value — a quick way to confirm this tool and your shell agree. Add a trailing newline (`echo hello` instead of `printf`) and every digest changes completely, which shows why a stray newline is a common cause of "the hash doesn't match". ## Limits and gotchas - **MD5 and SHA-1 are not collision-resistant.** Use them only for compatibility, never to guard against a motivated attacker. - **Text is hashed as UTF-8.** A system that hashes the same characters as UTF-16 or Latin-1 will get a different digest. - **Trailing whitespace and newlines count.** They are part of the input. - **Not a password hash.** Storing user passwords needs a slow, salted function such as bcrypt, scrypt, or Argon2 — a raw SHA digest is unsuitable. - **Large files** are read into memory before hashing; extremely large files can exhaust the tab. ## How to use - **Enter text or choose a file** — Type or paste text, or click "Hash a file instead" to hash a file from your device. - **Pick an output encoding** — Lowercase hex is the default and matches most command-line tools. Uppercase hex and Base64 are also available. - **Read all four digests** — MD5, SHA-1, SHA-256, and SHA-512 are computed together and shown in a table. - **Copy the one you need** — Each row has its own copy button. Compare against a published checksum to verify a download. ## Frequently asked questions ### Which hash should I use? For integrity checks and general use, SHA-256. Use SHA-512 if a spec calls for it. MD5 and SHA-1 are here only for compatibility with old systems and published legacy checksums — do not use them where an attacker could try to engineer a collision, because practical collision attacks exist for both. ### My file's hash doesn't match the one on the download page. Check three things: that the download completed (a truncated file hashes differently), that you are comparing the same algorithm (a SHA-256 sum won't match a SHA-1 sum), and that you didn't hash the wrong file. If the site offers a signature (.asc) as well as a checksum, the signature is the stronger check. ### Is hashing the same as encrypting? No. A hash is one-way — you cannot recover the input from the digest — and has no key. Encryption is reversible with a key. Hashes are for integrity and fingerprinting; they are not a way to hide data. A short or low-entropy input can often be recovered by brute force regardless. ### Why is there no MD5 in the browser's built-in crypto? The Web Crypto API (SubtleCrypto.digest) deliberately omits MD5 because it is broken for security purposes. This tool computes SHA-1/256/512 with SubtleCrypto and MD5 with a small bundled JavaScript implementation, so the MD5 row is there when you genuinely need it for a legacy checksum. --- *Source: [https://devtools.nicxon.tech/tools/hash-generator/](https://devtools.nicxon.tech/tools/hash-generator/) — generated by devtools.nicxon.tech.* --- # HMAC generator > Compute a keyed HMAC over a message using SHA-1, SHA-256, SHA-384, or SHA-512. ## What this does HMAC (Hash-based Message Authentication Code) combines a message and a secret key into a fixed-size tag using a hash function. This tool computes HMAC-SHA1, HMAC-SHA256, HMAC-SHA384, and HMAC-SHA512 with the browser's [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign). The key can be entered as UTF-8 text, hex, or Base64, and the tag can be shown as hex or Base64, so you can reproduce whatever format the system you're integrating with uses. Everything runs locally. Nothing about the key or message is transmitted. ## When you'd use it - Verifying an incoming webhook signature (Stripe, GitHub, Shopify, Slack, and many others sign their payloads with HMAC-SHA256). - Signing an outgoing API request that uses a shared-secret scheme (for example AWS SigV4-style or older HMAC auth). - Generating a tamper-evident token or a signed URL parameter. - Debugging a signature mismatch by isolating which input — body, key encoding, output encoding — is wrong. ## Worked example Message `id=42&amount=1000`, key `topsecret` (as UTF-8 text), HMAC-SHA256, hex output: ``` 641bedff29f7168bc87504b5927bf20598fcf9cd5a4f5022b8317310f0de54a9 ``` Switch the output to Base64 and the same 32 bytes become `ZBvt/yn3FovIdQS1knvyBZj8+c1aT1AiuDFzEPDeVKk=` — this is exactly the choice that trips people up when a provider's header is Base64 but their example code prints hex. Change the key encoding to "Hex" without changing the key text and the result changes completely, because `topsecret` is no longer valid hex and the bytes it decodes to are different. Reproduce the provider's documented example first; once that matches, your real payload will too. ## Limits and gotchas - **Sign the exact bytes.** For webhooks, that usually means the raw request body before any JSON parsing or reformatting. - **Key encoding is not cosmetic.** The same characters interpreted as text, hex, or Base64 are three different keys. - **Output encoding must match** the value you compare against, including any provider prefix like `sha256=`. - **Production comparisons must be constant-time.** Don't ship a plain `===` check. - **HMAC-SHA1** is still cryptographically acceptable for HMAC use, but choose SHA-256 for anything new unless a spec forces SHA-1. - **This is authentication, not encryption.** The message is not hidden; HMAC only detects tampering and proves origin. ## How to use - **Choose the hash** — SHA-256 is the usual choice. SHA-1, SHA-384, and SHA-512 are also available for matching an existing implementation. - **Enter the message and key** — Paste the exact message bytes and the shared secret. Set "Key encoding" if your secret is hex or Base64 rather than text. - **Pick the output encoding** — Hex or Base64, to match what you are comparing against. - **Compare** — Compute the HMAC and compare it to the value in the webhook header or API signature you are verifying. ## Frequently asked questions ### What is the difference between a hash and an HMAC? A plain hash of message can be recomputed by anyone. An HMAC mixes a secret key into the hashing process, so only someone who holds the key can produce or check the value. That is what makes it a message authentication code: it proves both that the message wasn't altered and that it came from someone with the key. ### My HMAC doesn't match the webhook's signature header. The usual causes: (1) hashing the wrong bytes — many providers sign the exact raw request body, so re-serialising the JSON changes it; (2) wrong key encoding — the secret might be hex or Base64, not text; (3) the provider prefixes the value (for example sha256=) or uses Base64 while you used hex; (4) a timestamp or other field is concatenated with the body before signing. Check the provider's signing recipe precisely. ### Why can't I just use == to compare two HMACs in my own code? A normal string comparison returns as soon as it finds a differing byte, which leaks timing information an attacker can use to recover the correct value byte by byte. Use a constant-time comparison function (crypto.timingSafeEqual in Node, hmac.compare_digest in Python). Comparing here in the browser for debugging is fine; the production check needs to be constant-time. ### Is the secret I type sent anywhere? No. The key and message are passed to the browser's SubtleCrypto HMAC implementation locally. Nothing leaves the page. Still, prefer a test key over your real production secret when you can. --- *Source: [https://devtools.nicxon.tech/tools/hmac-generator/](https://devtools.nicxon.tech/tools/hmac-generator/) — generated by devtools.nicxon.tech.* --- # JSON formatter & validator > Pretty-print or minify JSON and get the exact line and column of any syntax error. ## What this does This tool parses JSON and re-serializes it with consistent indentation, or collapses it to a single line. Parsing uses the browser's native `JSON.parse`, so "valid here" means "valid to every standards- compliant JSON parser". If parsing fails, the error is translated from a raw character offset into a **line and column** so you can find the problem without counting characters. An optional pass sorts object keys recursively, which is handy when you want to diff two documents that contain the same data in a different order. Everything runs in your browser. A 4,000-line configuration file, an API response with customer records, or a service-account key can be pasted here without any of it being transmitted — there is no server to transmit it to. ## When you'd use it - Making a minified API response readable while debugging. - Pretty-printing a JSON string that was logged on one line. - Checking whether a hand-edited config file is still valid before you deploy it. - Minifying a JSON fixture to embed it in a source file or a URL. - Normalising key order so `git diff` on two JSON files shows only real changes. ## Worked example Paste this (note the trailing comma): ``` {"service":"auth","retries":3,"hosts":["a","b",],"debug":false} ``` The tool reports: `Unexpected token ] — line 1, column 44`. Column 44 is the `]`; the character before it is a comma with no value after it. Remove the comma: ``` {"service":"auth","retries":3,"hosts":["a","b"],"debug":false} ``` With indent set to 2 spaces, the output becomes: ``` { "service": "auth", "retries": 3, "hosts": [ "a", "b" ], "debug": false } ``` Switching indent to *Minify* returns the compact form, now with the comma fixed, at 60 bytes. ## Limits and gotchas - **Strict JSON only.** No comments, no trailing commas, no single quotes, no unquoted keys, no `NaN` or `Infinity`. Those are JSON5 or JavaScript object literals, not JSON. - **Number precision.** Integers beyond 2^53 and high-precision decimals are rounded to the nearest double on parse. Carry those as strings. - **Key order.** Re-serialization preserves insertion order unless you enable "Sort keys". Duplicate keys in the input are collapsed to the last value, per `JSON.parse` behaviour. - **Very large documents.** Formatting is synchronous. Tens of megabytes of JSON will briefly block the tab while it parses. - **Not a schema validator.** This checks syntax, not whether your document matches an expected shape. Use a JSON Schema validator for that. ## How to use - **Paste your JSON** — Paste or type JSON into the input box. Formatting runs as you type. - **Choose an indent** — Pick 2 spaces, 4 spaces, a tab, or Minify to strip all whitespace. - **Read the result** — The formatted JSON appears on the right with a byte count, or an error message with the exact line and column if the JSON is invalid. - **Copy or fix** — Copy the output, or jump to the reported line and column to fix the syntax error. ## Frequently asked questions ### Why does it say “Unexpected token” with a line and column? That is a JSON syntax error at that position. The most common causes are a trailing comma after the last item in an object or array, a single quote used instead of a double quote, an unquoted key, or a missing comma between two items. Go to the reported line and column and check the character just before it. ### It rejects my JSON that has comments — is that a bug? No. The JSON specification does not allow comments, and this tool validates strict JSON. Files like tsconfig.json are actually JSONC (JSON with Comments), which is a different format. Strip // and /* */ comments before formatting, or use a JSON5/JSONC-aware editor. ### Are my numbers safe from being changed? Large integers can lose precision. JSON.parse reads numbers into IEEE-754 doubles, so any integer above 2^53 (for example a Twitter-style 64-bit ID) is rounded. If you see a number ending in unexpected zeros, that value should be transported as a string. ### Does “Sort keys” change the meaning of my JSON? For most consumers, no — object member order is not significant in JSON. It can matter if a downstream system does a naive string comparison of serialized objects, or signs the raw bytes. Sort keys is useful precisely for making two objects comparable, but do not apply it to a payload whose signature was computed over a specific byte sequence. --- *Source: [https://devtools.nicxon.tech/tools/json-formatter/](https://devtools.nicxon.tech/tools/json-formatter/) — generated by devtools.nicxon.tech.* --- # JSON ↔ YAML converter > Convert between JSON and YAML in either direction, preserving types and key order. ## What this does This converter parses one format into an in-memory data structure and serializes it as the other. JSON is parsed with the native `JSON.parse`; YAML is parsed with [js-yaml](https://github.com/nodeca/js-yaml) using its JSON-compatible schema, which keeps type coercion predictable. Because both formats describe the same underlying model — maps, sequences, strings, numbers, booleans, null — the conversion is lossless for data, though format-only details like comments, blank lines, and quote style are not carried across. It runs entirely in your browser. Kubernetes manifests, CI pipeline definitions, and application config with secrets in them can be converted here without leaving the page. ## When you'd use it - Turning a JSON API response into YAML to paste into a config file. - Converting a Docker Compose or GitHub Actions YAML file to JSON so a script can read it with a standard parser. - Checking whether a hand-written YAML file parses to the structure you expect by viewing it as JSON. - Normalising a YAML file's formatting by round-tripping it through the tool. ## Worked example Input (JSON): ``` {"service":"web","replicas":3,"env":[{"name":"LOG_LEVEL","value":"info"}],"tls":true} ``` Output (YAML): ``` service: web replicas: 3 env: - name: LOG_LEVEL value: info tls: true ``` Converting that YAML back to JSON with 2-space indent returns the original object exactly. Now change `value: info` to `value: yes` in the YAML and convert to JSON: you get `"value": true`, because bare `yes` is a YAML boolean. Quote it as `value: "yes"` and it stays the string `"yes"`. ## Limits and gotchas - **Comments and layout are not preserved** in either direction. - **YAML-only types** such as `!!timestamp`, `!!binary`, and custom tags are not represented in JSON and will error or be stringified. - **Multi-document YAML** (files separated by `---`) is not supported; convert one document at a time. - **Key order** is preserved as written. JSON object keys and YAML mapping keys both keep insertion order here. - **Very deep or very large documents** are converted synchronously and will briefly block the tab. - This is a syntax converter, not a schema or policy validator — it will happily convert a manifest that your cluster would reject. ## How to use - **Paste JSON or YAML** — Paste either format into the input box. The direction is auto-detected from the first non-whitespace character. - **Confirm the direction** — If auto-detection is wrong, set the Direction dropdown to JSON → YAML or YAML → JSON explicitly. - **Adjust output options** — For YAML → JSON, choose an indent width or minify. YAML output uses a fixed 2-space indent. - **Copy the result** — Copy the converted output, or click "Use output as input" to round-trip and check nothing was lost. ## Frequently asked questions ### Why did my YAML comments disappear? YAML comments are not part of the parsed data model — they exist only in the source text. Any converter that goes YAML → data → JSON or YAML → data → YAML drops them. If comments matter, keep the original file and treat the converted version as generated. ### My string "yes" / "no" / "on" turned into true / false. That is the YAML 1.1 boolean rule, which treats yes, no, on, off, and y/n as booleans. This tool loads YAML with the JSON-compatible schema to reduce that surprise, but if you are reading YAML produced elsewhere, quote those values ("yes") to keep them as strings. ### Numbers like 007 or 1.10 came back different. YAML and JSON both parse 007 as the integer 7 and 1.10 as the number 1.1 — the leading and trailing zeros are not preserved because they carry no numeric meaning. Values where the exact text matters (version strings, zip codes, phone numbers) must be quoted so they stay strings. ### Can it handle YAML anchors and aliases? On input, yes — anchors (&name) and aliases (*name) are resolved and the referenced data is expanded inline in the JSON output. On output, this tool does not emit anchors; repeated structures are written out in full. --- *Source: [https://devtools.nicxon.tech/tools/json-yaml/](https://devtools.nicxon.tech/tools/json-yaml/) — generated by devtools.nicxon.tech.* --- # JWT decoder > Decode a JSON Web Token's header and payload, expand standard claims, and flag alg:none and expired tokens. ## What this does A JSON Web Token is three base64url-encoded segments joined by dots: `header.payload.signature`. This tool splits the token, decodes the header and payload to readable JSON, and explains the registered claims — `iss`, `sub`, `aud`, `exp`, `nbf`, `iat`, `jti` — converting the numeric timestamps to readable UTC. It then runs a few safety checks and, for HMAC tokens, can verify the signature if you supply the secret. All of this happens in your browser. You can paste a live session token from your own application to see exactly what your auth server put in it. ## Reading the signature segment The third segment is a signature or a MAC over `base64url(header) + "." + base64url(payload)`. The `alg` field in the header says how it was produced: - **HS256 / HS384 / HS512** — HMAC with a shared secret. The same secret both signs and verifies, so it must never be shipped to a browser or a third party. - **RS256 / PS256 / ES256** — asymmetric. The issuer signs with a private key; anyone can verify with the public key. This is what you want when the verifier and the signer are different parties. - **none** — no signature at all. Treat its presence on an auth token as a bug or an attack. Decoding never checks the signature by itself. A JWT you pulled from a log is just as decodable whether or not it was tampered with — the decoded payload tells you what someone *claims*, not what is *true*. Only signature verification against the correct key makes it trustworthy. ## Why alg: none and algorithm confusion matter Two classic JWT vulnerabilities both come from trusting the token to tell you how to verify it. The first is `alg: none`: if your library honours it, an attacker strips the signature, edits the payload, and walks in. The second is **RS256-to-HS256 confusion**: the server expects an RS256 token and verifies with the RSA public key, which is not secret. An attacker changes the header to `HS256` and signs the token using that public key's bytes as the HMAC secret. A naïve verifier that reads `alg` from the token then "verifies" the forgery. The fix for both is the same: the verifier decides the algorithm and the key out of band, and rejects any token whose header disagrees. ## Worked example Load the sample token. The header is `{"alg":"HS256","typ":"JWT"}` and the payload includes `"iss":"auth.example.com"`, `"aud":"api"`, `"exp":1700003600`, and `"role":"admin"`. The claims table converts `exp` to a UTC time and explains that `aud` must equal your service's identifier or the token should be rejected. Because that sample `exp` is in the past, the status line reports the token as expired. Enter any secret in the verify field and the tool reports the signature does not match — the sample signature is illustrative, not real. ## Limits and gotchas - **No asymmetric verification.** RS/PS/ES signatures can't be checked here without the issuer's public key; only HS256/384/512 are supported. - **Clock skew.** The expired / not-yet-valid checks use your device clock. Real verifiers usually allow a small leeway (30–60 seconds). - **Decoding is not validation.** A well-formed token can still be forged, revoked, or issued by the wrong party. - **Encrypted tokens (JWE)** have five segments and are not decodable without the key; this tool handles signed tokens (JWS) only. - **Sensitive payloads.** Anything in the payload is readable by anyone who holds the token. Don't put secrets in claims. ## How to use - **Paste the token** — Paste the full JWT — three dot-separated segments — into the input box. - **Read the header and payload** — The decoded header and payload JSON appear side by side. Registered claims are explained in the table below. - **Check the warnings** — The status line flags alg:none, a missing exp claim, an expired token, and a not-yet-valid (nbf) token. - **Optionally verify the signature** — For HS256/384/512 tokens, paste the shared secret to check the signature locally. The secret is never sent anywhere. ## Frequently asked questions ### Does decoding a JWT here reveal it to anyone? No. The token is split and base64url-decoded in your browser with JavaScript. Nothing — not the token, not the payload, not a secret you enter for verification — is sent to a server. That is the point of doing it client-side: you can safely inspect a real production token. ### Why is "alg": "none" dangerous? A JWT with alg: none has no signature. The standard allows it for cases where the token's integrity is guaranteed by other means, but if an application accepts it on a normal auth path, an attacker can craft any payload they like — admin: true, someone else's user ID — and it will be trusted. Several real libraries historically accepted none by default. Your verification code must pin the expected algorithm and reject anything else, including none. ### The payload looks fine but is the token actually valid? Decoding only proves the token is well-formed. A token is valid only if the signature verifies against the issuer's key and the claims check out: exp in the future, nbf in the past, iss is who you expect, and aud contains your service. This tool checks the time-based claims and can verify an HMAC signature; it cannot verify RS/ES/PS signatures because it doesn't have the issuer's public key. ### What is the difference between the "alg none" warning and an expired warning? "alg none" is a structural red flag about how the token is signed — it should almost never appear on a real token. "Expired" means the token was legitimately issued but its exp timestamp has passed, so a correct server will now reject it. Both cause the status line to turn amber, but they are different problems: one is a possible attack, the other is normal token lifecycle. --- *Source: [https://devtools.nicxon.tech/tools/jwt-decoder/](https://devtools.nicxon.tech/tools/jwt-decoder/) — generated by devtools.nicxon.tech.* --- # Regex tester > Test a JavaScript regular expression against sample text and inspect every match and capture group. ## What this does This compiles your pattern into a JavaScript `RegExp` with the flags you choose and runs it against the test string. Every match is highlighted in place, and a table breaks each match down into its overall text, its start offset, and the contents of every capture group — numbered groups and `(?…)` named groups alike. Invalid patterns report the engine's own syntax error. There is no backend. The regex and the text never leave the page, so you can test against real log lines or user data. ## Flags, briefly - **g** — find all matches, not just the first. - **i** — case-insensitive. - **m** — `^` and `$` match at line breaks, not just string start/end. - **s** — `.` also matches newline characters. - **u** — treat the pattern as Unicode; needed for `\p{...}` property escapes and correct handling of astral characters. - **y** — sticky; matches only at `lastIndex`, useful for tokenisers. ## Worked example Pattern (the default), with the `g` flag: ``` (\w+)@(\w+)\.(\w{2,}) ``` Test string: ``` Contact ada@example.com or grace@dev.io for access. ``` Two matches. For `ada@example.com` the groups are `1: ada`, `2: example`, `3: com`; for `grace@dev.io` they are `grace`, `dev`, `io`. Add the `i` flag and an address with capital letters would also match. Give the groups names: ``` (?\w+)@(?\w+)\.(?\w{2,}) ``` and the table shows `group `, `group `, and `group ` alongside the numbered ones. ## Limits and gotchas - **ECMAScript semantics.** Patterns from other languages may need adjustment. - **Backslashes are literal in the input box.** Enter `d`, not the doubled `\d` you'd write inside a JavaScript string literal. - **Empty-match patterns** match everywhere; anchor or require a character. - **Catastrophic backtracking** can freeze the tab. Avoid nested quantifiers over overlapping classes. - **The `g` flag changes `exec` behaviour** — the tool manages `lastIndex` for you, but remember that in your own code a shared `/g` regex is stateful. ## How to use - **Enter a pattern** — Type the regular expression body — no surrounding slashes. Backslashes are literal here (write \d, not \\d). - **Set flags** — Toggle g, i, m, s, u, and y as checkboxes. g is on by default so you see every match. - **Paste test text** — Put the sample string in the text box. Matches highlight as you type. - **Inspect the groups** — The table lists each match with its start index and every numbered and named capture group. ## Frequently asked questions ### Whose regex flavour is this? JavaScript's (ECMAScript). It is close to PCRE for everyday patterns but differs in details: no possessive quantifiers, no recursion, different Unicode property syntax, lookbehind is supported in modern engines, and named groups use (?...). A pattern copied from a Python or PHP codebase may need small changes. ### My pattern with an empty match hangs or floods with matches. A pattern that can match an empty string (for example a*) will match at every position. This tool advances past zero-length matches and caps the loop, but the result is usually not what you want — anchor the pattern or require at least one character (a+). ### Why does group 2 show "undefined"? That capture group did not participate in the match — commonly because it was inside an alternation ((a)|(b)) and the other branch matched, or inside an optional group that was skipped. Undefined is different from an empty string match; the tool distinguishes them. ### Is there a catastrophic-backtracking risk? Yes, in any regex engine. Nested quantifiers over overlapping character classes (the classic (a+)+$ against a long non-matching string) can take exponential time. Testing here runs on your machine, so a bad pattern freezes your tab rather than a server, but the lesson transfers: restructure the pattern or add anchors. --- *Source: [https://devtools.nicxon.tech/tools/regex-tester/](https://devtools.nicxon.tech/tools/regex-tester/) — generated by devtools.nicxon.tech.* --- # Text diff > Compare two blocks of text and see additions and deletions highlighted at the word level. ## What this does This computes the difference between two blocks of text and renders it inline: removed spans struck through, added spans highlighted, everything else untouched. It uses [jsdiff](https://github.com/kpdecker/jsdiff), which implements the standard Myers diff algorithm, at three granularities — whole lines, whole words (keeping whitespace), or individual characters. Options let you fold away case-only and surrounding-whitespace-only differences. It runs in your browser. Two drafts of a contract clause, two versions of a log, or a config diff with credentials in it can all be compared without anything being sent anywhere. ## When you'd use it - Comparing two API responses to see exactly which field changed. - Checking what an automated formatter or a find-and-replace actually altered. - Reviewing an edit to a piece of copy, an email, or documentation. - Spotting the one character that differs between a working and a broken config value. - Diffing text you can't paste into a hosted tool for confidentiality reasons. ## Worked example Left: ``` The quick brown fox jumps over the lazy dog. ``` Right: ``` The quick red fox leaps over the lazy dog! ``` In **Word** mode the diff reads: "The quick brownred fox jumpsleaps over the lazy dog.!" — three small changes, each shown exactly where it happens. Switch to **Line** mode and, because the single line changed at all, the whole line is marked removed and the whole new line added — more faithful to how a line-oriented tool sees it, less useful for reading. **Character** mode would additionally show that `jumps` → `leaps` keeps the `s` at the end. ## Limits and gotchas - **Not a merge or patch tool.** No three-way merge, no conflict markers, no unified-diff export. - **Large inputs.** Character-mode diffing of very large texts is O(n·d) and can be slow; drop to Word or Line mode. - **Whitespace and line endings** are real differences unless you enable the ignore option. Mixed ` `/` ` is a frequent false positive. - **Moved blocks** show as a deletion in one place and an insertion in another; the tool doesn't detect that a paragraph was relocated. - **Unicode.** Combining characters and emoji sequences may split in Character mode in ways that look odd; Word mode is safer for those. ## How to use - **Paste both versions** — Put the original on the left and the changed text on the right. - **Choose granularity** — Word for prose, Line for code or config, Character for small precise edits. - **Set the ignore options** — Optionally ignore case, or ignore leading and trailing whitespace, to hide changes you do not care about. - **Read the inline diff** — Deletions are struck through in red, insertions are highlighted in green, unchanged text is left plain. ## Frequently asked questions ### Word, line, or character — which should I pick? Line for source code, config files, and anything where a line is the unit of meaning. Word for paragraphs of prose, where line-level diffing would mark a whole rewrapped paragraph as changed. Character for spotting a single transposed letter or a changed digit in an otherwise identical string. ### Two visually identical texts show as different. Almost always an invisible character: trailing spaces, a tab vs spaces, Windows \r\n vs Unix \n line endings, a non-breaking space pasted from a web page, or a Unicode look-alike. Try Line mode with "ignore leading/trailing whitespace", and if it still differs, use Character mode to find the exact spot. ### Is this a real merge tool? No. It shows what changed between two texts; it does not do three-way merges, conflict resolution, or produce a patch file. It is for eyeballing differences — comparing two API responses, two versions of a message, a config before and after an edit. ### Does the diff match what git would show? The set of changed regions is usually the same, but the presentation differs. Git shows whole changed lines with +/- prefixes; this tool shows changes inline, and in Word or Character mode it highlights sub-line edits that a default git diff would show as a full line replacement. --- *Source: [https://devtools.nicxon.tech/tools/text-diff/](https://devtools.nicxon.tech/tools/text-diff/) — generated by devtools.nicxon.tech.* --- # Unix timestamp converter > Convert Unix seconds or milliseconds to a human date in any time zone, and back. ## What this does Unix time counts the seconds (or milliseconds) since 1970-01-01T00:00:00Z. This tool converts a Unix number to a full set of readable forms, and parses a calendar date back into Unix seconds and milliseconds. Time-zone maths uses the browser's `Intl.DateTimeFormat` with the IANA database, so historical offset changes and daylight-saving rules for the selected zone are applied correctly. No network calls — the conversion and the zone data both come from your browser. ## When you'd use it - Making sense of a timestamp in a log line, a database row, or a JWT's `exp` claim. - Producing a Unix value to paste into a query or a config that expects one. - Checking what "now" is in epoch form for a quick test. - Working out whether an `iat`/`exp` pair is minutes or hours apart. - Converting a meeting time in one zone to UTC for a cron schedule. ## Worked example Enter `1700000000` with the zone set to UTC: ``` Unix seconds 1700000000 Unix milliseconds 1700000000000 ISO 8601 (UTC) 2023-11-14T22:13:20.000Z Local to UTC Tuesday, 14 November 2023 at 22:13:20 UTC RFC / UTC string Tue, 14 Nov 2023 22:13:20 GMT Relative (depends on today) ``` Switch the zone to `Africa/Nairobi` and the "Local" row becomes `15 November 2023 at 01:13:20 GMT+3` — same instant, next calendar day. Now type `2023-11-15 01:13:20` into the date box with the zone still on Nairobi and the left box reads `1700000000` again, confirming the round trip. Change the zone to UTC without changing the text and the timestamp shifts by three hours, because the same wall-clock string now denotes a different instant. ## Limits and gotchas - **Timestamps carry no zone.** The zone selector controls interpretation of typed dates and the display of results, not the underlying instant. - **Unit detection is heuristic.** Override it by adjusting the digit count when a value sits near a boundary. - **Ambiguous local times.** During a DST "spring forward" gap or "fall back" overlap, a wall-clock string can map to no instant or two; the tool picks one. - **Browser zone data.** Results depend on the IANA data shipped with your browser; a very old browser may have stale rules for some zones. - **Not a duration calculator.** It converts single instants, not intervals between them. ## How to use - **Enter a timestamp or a date** — Type a Unix number in the left box, or a date string in the right box. The other side updates. - **Set the time zone** — Pick the IANA zone the date should be read in or displayed in. UTC is the default. - **Read every representation** — The table shows Unix seconds and milliseconds, ISO 8601 UTC, the local time in your zone, an RFC string, and a relative phrase. - **Copy the ISO value** — Use the copy button for the ISO 8601 string, which is the safest format to store or transmit. ## Frequently asked questions ### Is my number in seconds or milliseconds? This tool guesses by length: about 10 digits is seconds, about 13 is milliseconds, about 16 is microseconds. A 10-digit value lands in 2001–2286; a 13-digit value that you treat as seconds would land tens of thousands of years in the future, which is the tell. If your number is near a boundary, set it explicitly by adding or removing three zeros. ### Why does the same timestamp show a different date for someone else? A Unix timestamp is an absolute instant — it has no time zone. The calendar date it corresponds to depends on the zone you view it in. 1700000000 is 2023-11-14 22:13:20 in UTC, but 2023-11-15 in Nairobi and still 2023-11-14 in New York. Always record which zone a displayed date was in. ### I entered "2023-11-14 22:13" and got an unexpected instant. A date string with no offset is ambiguous. This tool resolves it in the zone you selected. If you paste a string that does carry an offset or a trailing Z, that wins and the zone selector only affects the display. Mixing the two is the usual cause of a one-to-twelve-hour error. ### Does it handle dates before 1970 or leap seconds? Negative timestamps (before 1970) work. Leap seconds do not exist in Unix time — the count is defined as seconds since the epoch ignoring leap seconds, so 23:59:60 UTC on a leap-second day is not representable, same as in every mainstream language runtime. --- *Source: [https://devtools.nicxon.tech/tools/timestamp/](https://devtools.nicxon.tech/tools/timestamp/) — generated by devtools.nicxon.tech.* --- # URL encoder & decoder > Percent-encode or decode a full URL, a query component, or a single path segment. ## What this does Percent-encoding (also called URL-encoding) replaces characters that are unsafe or reserved in a URL with a `%` followed by their byte value in hexadecimal. This tool applies the three standard JavaScript behaviours — `encodeURIComponent`, `encodeURI`, and form-style encoding where space becomes `+` — and reverses each. Non-ASCII characters are encoded as their UTF-8 bytes, so `é` becomes `%C3%A9`. It's all client-side. You can paste a full URL with an auth token or a customer identifier in the query string and nothing is sent anywhere. ## When you'd use it - Building a query string by hand and needing to escape a value that contains `&`, `=`, or a space. - Reading a redirect URL where the `return_to` parameter is itself an encoded URL. - Debugging why a link breaks — often because a value wasn't component-encoded and its `&` split the query string. - Decoding a copied URL so you can read the parameters, then re-encoding after editing one. ## Worked example You want `q` to be the search phrase `tabs & spaces` and `next` to be the path `/settings?tab=1`. Component-encode each value: ``` tabs%20%26%20spaces %2Fsettings%3Ftab%3D1 ``` Assemble the URL: ``` https://example.com/search?q=tabs%20%26%20spaces&next=%2Fsettings%3Ftab%3D1 ``` Because the `&` and `?` inside the values were escaped, the browser sees exactly two parameters. Feed the whole thing back through Decode (Component scope on just each value) to recover the originals. If instead you had used Full URL scope on the values, the `&` would have stayed literal and `next` would have been truncated. ## Limits and gotchas - **Scope matters.** Encoding a whole URL with Component scope escapes the `://` and slashes, producing a string that is no longer a usable URL. - **Plus vs percent-twenty.** Decoding form data with the wrong scope leaves `+` signs as literal pluses or turns real pluses into spaces. - **Reserved but not escaped.** `encodeURI` leaves `&`, `+`, `,`, and `#` alone by design; those still need manual attention inside a value. - **Non-UTF-8 input.** The encoders assume UTF-8. Legacy encodings like Latin-1 will produce different bytes than a system expecting them would. - **It doesn't validate URLs.** A well-encoded string can still be a nonsense URL. ## How to use - **Pick encode or decode** — Encode turns text into percent-escapes; Decode turns them back. - **Choose the scope** — Component for a single query value or path segment, Full URL to keep structural characters, or Form for application/x-www-form-urlencoded. - **Paste your text** — Enter the string in the input box. Conversion runs as you type. - **Copy the result** — Copy the output, or use "Use output as input" to reverse the operation and check it round-trips. ## Frequently asked questions ### When do I use "Component" versus "Full URL"? Use Component (encodeURIComponent) when the text is a single piece that goes inside a URL — one query-string value, one path segment. It escapes /, ?, &, =, and # so they can't be mistaken for structure. Use Full URL (encodeURI) only when you have a whole URL and just want to fix spaces and non-ASCII while leaving the ://, slashes, and ? intact. ### Why is a space sometimes %20 and sometimes +? In a URL path or a generic component, a space is %20. In application/x-www-form-urlencoded data — the body of a classic HTML form POST, and often the query string — a space is +. They are not interchangeable in every context. The Form scope here produces and reads +; the other scopes use %20. ### Decoding threw "URI malformed". What does that mean? The input contains a % that isn't followed by two valid hex digits, or a percent-escape that doesn't form a valid UTF-8 sequence. A literal percent sign in text must itself be written as %25 before the string can be decoded. ### Does it double-encode if I run encode twice? Yes. Encoding a b gives a%20b; encoding that again gives a%2520b because the % is now escaped. Double-encoding is a common bug when a value passes through two layers that both encode. Decode the same number of times you encoded. --- *Source: [https://devtools.nicxon.tech/tools/url-encode/](https://devtools.nicxon.tech/tools/url-encode/) — generated by devtools.nicxon.tech.* --- # UUID & ULID generator > Generate cryptographically random UUID v4 values and lexicographically sortable ULIDs in bulk. ## What this does This generates identifiers in bulk using the browser's cryptographically secure random number generator. **UUID v4** is the familiar `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` form defined by RFC 4122, with 122 bits of randomness. **ULID** is a 26-character Crockford-Base32 string: a 48-bit millisecond timestamp followed by 80 random bits, designed so that sorting the strings sorts by time. Generation is entirely local — `crypto.randomUUID()` and `crypto.getRandomValues()` — so nothing is fetched and no two users can receive the same value from a shared server. ## When you'd use it - Seeding test data or fixtures that need realistic-looking IDs. - Creating a correlation ID for a log trace or a request you're debugging. - Generating primary keys for a migration or a one-off script. - Producing an idempotency key for an API call. - Filling in a config value that expects a UUID (a client ID, a namespace). ## Worked example Generate 3 UUID v4 values: ``` b1e7c0a2-4f3d-4a6b-9c21-7d8e5f0a1b2c 0f9a8b7c-1d2e-4f30-8a1b-2c3d4e5f6071 7c6b5a49-3827-4160-95a4-b3c2d1e0f9a8 ``` Tick "Remove dashes" and "Uppercase" and the first becomes `B1E7C0A24F3D4A6B9C217D8E5F0A1B2C` — the compact form some systems store. Switch to ULID and generate 3: ``` 01J9Z8QK3M4N5P6Q7R8S9T0V1W 01J9Z8QK3M7X8Y9Z0A1B2C3D4E 01J9Z8QK3MF5G6H7J8K9M0N1P2 ``` All three share the same leading characters because they were created in the same millisecond; the tails differ. Sort them as plain strings and they stay in a sensible order — that's the property a random UUID doesn't give you. ## Limits and gotchas - **ULIDs reveal creation time.** Don't use them where that timing is sensitive. - **No monotonic ULID mode.** ULIDs generated within the same millisecond are not guaranteed to sort in creation order relative to each other. - **UUID formatting is presentation only.** Removing dashes or uppercasing doesn't change the underlying value, but some parsers are strict about the canonical lowercase, dashed form. - **Not sequential integers.** If a system expects an auto-incrementing numeric ID, a UUID or ULID won't fit. - **Case sensitivity.** UUIDs are conventionally lowercase; ULIDs are uppercase Base32 and exclude the letters I, L, O, and U to avoid ambiguity. ## How to use - **Choose UUID v4 or ULID** — UUID v4 for a standard random identifier; ULID for one that also sorts by creation time. - **Set the count** — Enter how many you need, from 1 to 1000. - **Apply formatting \(UUID only\)** — Optionally uppercase, remove dashes, or wrap each value in braces. - **Generate and copy** — Click Generate, then "Copy all" to copy the whole list, one per line. ## Frequently asked questions ### Are these safe to use as unguessable tokens? UUID v4 has 122 random bits from the browser's cryptographic RNG (crypto.randomUUID), so it is effectively unguessable and fine as an opaque identifier. It is not a substitute for a real secret with rotation and revocation, but as a hard-to-enumerate key it is solid. ULID's random section has 80 bits, which is strong but lower; its timestamp portion is not secret at all. ### Why would I choose ULID over UUID? A ULID starts with a 48-bit millisecond timestamp, so lexical sort order matches creation order. That makes ULIDs pleasant as primary keys: inserts stay roughly sequential (kinder to B-tree indexes than fully random UUIDs) and you can eyeball which record is newer. The trade-off is that a ULID leaks its creation time. ### Will I ever get a duplicate? For UUID v4 the collision probability is negligible for any realistic volume — you would need on the order of a billion billion values before it becomes a practical concern. For ULIDs generated here, two created in the same millisecond are independent random values, so a collision needs an 80-bit clash within that millisecond, which is also negligible. This tool does not implement ULID monotonic mode, so same-millisecond ULIDs are not guaranteed to sort in generation order relative to each other. ### Which UUID version is this, and do you support v1 or v7? This generates version 4 (random). v1 embeds a MAC address and timestamp and is rarely wanted today. v7 is the newer time-ordered UUID that serves the same purpose as ULID; it is not generated here yet, but a ULID covers the same need with a shorter, case-insensitive string. --- *Source: [https://devtools.nicxon.tech/tools/uuid-ulid/](https://devtools.nicxon.tech/tools/uuid-ulid/) — generated by devtools.nicxon.tech.* --- *Generated by devtools.nicxon.tech. 13 tools included.*