<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kaifi Azam</title>
    <description>The latest articles on DEV Community by Kaifi Azam (@kaifi_azam_21).</description>
    <link>https://dev.to/kaifi_azam_21</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4052638%2F4a8c07e3-deb0-43f7-8b8f-8e8f1e59795d.png</url>
      <title>DEV Community: Kaifi Azam</title>
      <link>https://dev.to/kaifi_azam_21</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kaifi_azam_21"/>
    <language>en</language>
    <item>
      <title>How an Adaptive Typing Tutor Improves Accuracy Before Speed</title>
      <dc:creator>Kaifi Azam</dc:creator>
      <pubDate>Tue, 04 Aug 2026 10:22:12 +0000</pubDate>
      <link>https://dev.to/kaifi_azam_21/how-an-adaptive-typing-tutor-improves-accuracy-before-speed-12lm</link>
      <guid>https://dev.to/kaifi_azam_21/how-an-adaptive-typing-tutor-improves-accuracy-before-speed-12lm</guid>
      <description>&lt;p&gt;Most typing tests measure the final result.&lt;/p&gt;

&lt;p&gt;They tell you:&lt;/p&gt;

&lt;p&gt;How many words you typed per minute&lt;br&gt;
How many mistakes you made&lt;br&gt;
How accurate the completed text was&lt;/p&gt;

&lt;p&gt;Those numbers are useful, but they do not always explain what is holding you back.&lt;/p&gt;

&lt;p&gt;A learner might reach 50 words per minute while repeatedly mistyping the same letters. Another learner may appear accurate only because they use Backspace to repair every mistake before finishing.&lt;/p&gt;

&lt;p&gt;A better typing tutor should do more than display a score.&lt;/p&gt;

&lt;p&gt;It should identify weak keys, adjust the next lesson, track genuine first-attempt accuracy, and introduce new letters only when the learner is ready.&lt;/p&gt;

&lt;p&gt;That is the approach behind the Olivez Typing Tutor.&lt;/p&gt;

&lt;p&gt;In this article, we will explore:&lt;/p&gt;

&lt;p&gt;Why accuracy should come before speed&lt;br&gt;
What first-attempt accuracy means&lt;br&gt;
How adaptive typing practice works&lt;br&gt;
Why fixed passages are not enough&lt;br&gt;
How weak keys can influence lesson generation&lt;br&gt;
How progress can be stored locally&lt;br&gt;
How students can build a more effective practice routine&lt;br&gt;
Typing speed is only one part of the skill&lt;/p&gt;

&lt;p&gt;Typing speed is commonly measured in words per minute, usually written as WPM.&lt;/p&gt;

&lt;p&gt;A standard typing “word” is normally treated as five characters, including spaces and punctuation.&lt;/p&gt;

&lt;p&gt;A simplified calculation is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{WPM} =&lt;br&gt;
\frac{\text{characters typed}}{5 \times \text{minutes}}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;For example, if a student types 250 characters in one minute:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\frac{250}{5} = 50 \text{ WPM}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;That number describes output speed, but it does not reveal how smoothly the text was produced.&lt;/p&gt;

&lt;p&gt;Two students can both score 50 WPM while having very different typing habits.&lt;/p&gt;

&lt;p&gt;One may type with steady rhythm and few mistakes.&lt;/p&gt;

&lt;p&gt;The other may type quickly, pause frequently, make repeated errors, and rely heavily on Backspace.&lt;/p&gt;

&lt;p&gt;The final WPM score can hide those differences.&lt;/p&gt;

&lt;p&gt;Accuracy should come before speed&lt;/p&gt;

&lt;p&gt;Trying to type faster before building accurate finger movements can reinforce poor habits.&lt;/p&gt;

&lt;p&gt;Every repeated mistake teaches the learner something, even when the lesson is unintended.&lt;/p&gt;

&lt;p&gt;If a student consistently presses i instead of o, rushing through more passages may strengthen that incorrect movement.&lt;/p&gt;

&lt;p&gt;A more reliable learning sequence is:&lt;/p&gt;

&lt;p&gt;Accuracy → consistency → speed&lt;/p&gt;

&lt;p&gt;First, the correct finger should reach the correct key.&lt;/p&gt;

&lt;p&gt;Next, that movement should become repeatable.&lt;/p&gt;

&lt;p&gt;Only then should the learner increase speed.&lt;/p&gt;

&lt;p&gt;This is similar to learning a musical instrument. Practising a difficult section slowly and correctly is usually more effective than playing it quickly with the same mistake every time.&lt;/p&gt;

&lt;p&gt;Completed accuracy can hide mistakes&lt;/p&gt;

&lt;p&gt;Many typing applications calculate accuracy by looking only at the final text.&lt;/p&gt;

&lt;p&gt;Suppose the target word is:&lt;/p&gt;

&lt;p&gt;typing&lt;/p&gt;

&lt;p&gt;A learner enters:&lt;/p&gt;

&lt;p&gt;typimg&lt;/p&gt;

&lt;p&gt;They then press Backspace, replace the incorrect m with n, and finish with the correct word.&lt;/p&gt;

&lt;p&gt;The final text matches the target, but the learner still made a mistake on the first attempt.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;The corrected text shows the learner understood the target.&lt;/p&gt;

&lt;p&gt;The first keypress shows whether the movement was reliable.&lt;/p&gt;

&lt;p&gt;The Olivez Typing Tutor keeps first-attempt performance separate from visible corrections.&lt;/p&gt;

&lt;p&gt;Backspace can repair the text on screen, but it does not erase the original error from the learning statistics.&lt;/p&gt;

&lt;p&gt;This produces a more honest picture of which keys need practice.&lt;/p&gt;

&lt;p&gt;What first-attempt accuracy means&lt;/p&gt;

&lt;p&gt;First-attempt accuracy measures whether each character was typed correctly before any correction.&lt;/p&gt;

&lt;p&gt;A simplified formula is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{First-attempt accuracy} =&lt;br&gt;
\frac{\text{correct first keypresses}}&lt;br&gt;
{\text{total first keypresses}}&lt;br&gt;
\times 100&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Imagine a student attempts 100 characters.&lt;/p&gt;

&lt;p&gt;They type 92 correctly on the first attempt and initially mistype 8.&lt;/p&gt;

&lt;p&gt;Their first-attempt accuracy is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\frac{92}{100} \times 100 = 92%&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Even if they correct all eight mistakes with Backspace, the first-attempt score remains 92%.&lt;/p&gt;

&lt;p&gt;This helps distinguish between:&lt;/p&gt;

&lt;p&gt;Producing correct final text&lt;br&gt;
Producing correct movements automatically&lt;/p&gt;

&lt;p&gt;Both matter, but they describe different stages of learning.&lt;/p&gt;

&lt;p&gt;Why fixed typing passages have limits&lt;/p&gt;

&lt;p&gt;Fixed passages are useful for measuring general performance.&lt;/p&gt;

&lt;p&gt;They can test:&lt;/p&gt;

&lt;p&gt;Reading and transcription&lt;br&gt;
Punctuation&lt;br&gt;
Capital letters&lt;br&gt;
Word spacing&lt;br&gt;
Sustained typing&lt;br&gt;
Overall speed&lt;/p&gt;

&lt;p&gt;However, a fixed passage may not contain enough examples of the keys causing difficulty.&lt;/p&gt;

&lt;p&gt;If a learner struggles with b, p, and y, a generic paragraph may include those letters only a few times.&lt;/p&gt;

&lt;p&gt;The student can complete the exercise without receiving enough targeted practice to improve them.&lt;/p&gt;

&lt;p&gt;An adaptive tutor can instead generate lessons that contain weak keys more frequently.&lt;/p&gt;

&lt;p&gt;The goal is not to create meaningless repetition. It is to place difficult letters inside readable patterns and words so the learner practises the exact movements that need attention.&lt;/p&gt;

&lt;p&gt;How adaptive typing practice works&lt;/p&gt;

&lt;p&gt;An adaptive typing tutor changes the lesson based on recent performance.&lt;/p&gt;

&lt;p&gt;A simplified cycle looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The learner completes a lesson.&lt;/li&gt;
&lt;li&gt;The tutor records each attempted key.&lt;/li&gt;
&lt;li&gt;Correct and incorrect first attempts are counted.&lt;/li&gt;
&lt;li&gt;Frequently missed keys receive more weight.&lt;/li&gt;
&lt;li&gt;The next lesson includes those keys more often.&lt;/li&gt;
&lt;li&gt;Progress is reviewed before new letters are introduced.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This creates a feedback loop.&lt;/p&gt;

&lt;p&gt;Instead of giving every learner the same exercise, the tutor responds to individual performance.&lt;/p&gt;

&lt;p&gt;A student who struggles with r and t may receive more words containing those letters.&lt;/p&gt;

&lt;p&gt;A student who types them accurately but slowly may receive practice designed to improve rhythm.&lt;/p&gt;

&lt;p&gt;A student who has not collected enough attempts may continue practising the same active letter set before the system makes a strong judgement.&lt;/p&gt;

&lt;p&gt;Why evidence count matters&lt;/p&gt;

&lt;p&gt;A percentage can be misleading when it is based on very little data.&lt;/p&gt;

&lt;p&gt;Suppose a learner types the letter j correctly once.&lt;/p&gt;

&lt;p&gt;Their recorded accuracy for j would technically be 100%.&lt;/p&gt;

&lt;p&gt;That does not prove the key has been mastered.&lt;/p&gt;

&lt;p&gt;Compare these results:&lt;/p&gt;

&lt;p&gt;Key A: 1 correct attempt out of 1&lt;br&gt;
Key B: 97 correct attempts out of 100&lt;/p&gt;

&lt;p&gt;Key A has the higher percentage, but Key B has much stronger evidence.&lt;/p&gt;

&lt;p&gt;An adaptive learning system should therefore consider both:&lt;/p&gt;

&lt;p&gt;Accuracy&lt;br&gt;
Number of recorded attempts&lt;/p&gt;

&lt;p&gt;This prevents the tutor from unlocking new material based on one or two lucky keypresses.&lt;/p&gt;

&lt;p&gt;The Olivez Typing Tutor uses collected evidence alongside performance rather than relying on a percentage alone.&lt;/p&gt;

&lt;p&gt;Controlled letter unlocking&lt;/p&gt;

&lt;p&gt;Showing the entire keyboard immediately can overwhelm beginners.&lt;/p&gt;

&lt;p&gt;There are too many movements to remember at once, and mistakes become difficult to diagnose.&lt;/p&gt;

&lt;p&gt;A progressive typing tutor can begin with a smaller group of common letters.&lt;/p&gt;

&lt;p&gt;New letters are introduced only after the learner demonstrates sufficient control over the current set.&lt;/p&gt;

&lt;p&gt;The Olivez Typing Tutor evaluates factors such as:&lt;/p&gt;

&lt;p&gt;First-attempt accuracy&lt;br&gt;
Typing speed&lt;br&gt;
Amount of practice evidence&lt;br&gt;
Performance across active letters&lt;br&gt;
Recent weak keys&lt;/p&gt;

&lt;p&gt;A new letter should not unlock simply because one lesson was completed.&lt;/p&gt;

&lt;p&gt;The learner needs to show that the existing set is becoming reliable.&lt;/p&gt;

&lt;p&gt;This creates a more manageable learning path.&lt;/p&gt;

&lt;p&gt;A simplified unlocking rule&lt;/p&gt;

&lt;p&gt;An adaptive system might use conditions similar to these:&lt;/p&gt;

&lt;p&gt;const canUnlockNextLetter =&lt;br&gt;
    firstAttemptAccuracy &amp;gt;= 95 &amp;amp;&amp;amp;&lt;br&gt;
    currentSpeed &amp;gt;= targetSpeed &amp;amp;&amp;amp;&lt;br&gt;
    minimumEvidenceReached;&lt;/p&gt;

&lt;p&gt;The exact learning system can be more detailed, but the basic idea is clear.&lt;/p&gt;

&lt;p&gt;Progress should depend on demonstrated ability rather than time spent clicking through exercises.&lt;/p&gt;

&lt;p&gt;A learner who needs additional practice can remain on the current letter set.&lt;/p&gt;

&lt;p&gt;A learner who meets the conditions can move forward without repeating material unnecessarily.&lt;/p&gt;

&lt;p&gt;Identifying weak keys&lt;/p&gt;

&lt;p&gt;A weak key is not always the key with the lowest raw accuracy.&lt;/p&gt;

&lt;p&gt;Several factors may matter:&lt;/p&gt;

&lt;p&gt;Number of mistakes&lt;br&gt;
Number of total attempts&lt;br&gt;
Recent performance&lt;br&gt;
Time taken to type the key&lt;br&gt;
Whether the same error repeats&lt;br&gt;
Confusion with a nearby key&lt;br&gt;
Improvement or decline over time&lt;/p&gt;

&lt;p&gt;A simplified weakness score could combine error rate with evidence:&lt;/p&gt;

&lt;p&gt;function getWeaknessScore(&lt;br&gt;
    mistakes,&lt;br&gt;
    attempts,&lt;br&gt;
) {&lt;br&gt;
    if (attempts === 0) {&lt;br&gt;
        return 0;&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const errorRate =
    mistakes / attempts;

const confidence =
    Math.min(attempts / 20, 1);

return errorRate * confidence;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;The confidence factor prevents a key with one mistake from being treated as more important than a key with repeated errors across many attempts.&lt;/p&gt;

&lt;p&gt;This is only a simplified example, but it demonstrates why adaptive systems should consider both performance and sample size.&lt;/p&gt;

&lt;p&gt;Lesson generation around weak keys&lt;/p&gt;

&lt;p&gt;After weak keys are identified, the tutor can give them a greater chance of appearing in the next lesson.&lt;/p&gt;

&lt;p&gt;A basic weighted selection model might look like this:&lt;/p&gt;

&lt;p&gt;const keyWeights = {&lt;br&gt;
    a: 1,&lt;br&gt;
    s: 1,&lt;br&gt;
    d: 3,&lt;br&gt;
    f: 2,&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;In this example, d and f need more attention.&lt;/p&gt;

&lt;p&gt;The lesson generator can use the weights to include those letters more often while still mixing in stronger keys.&lt;/p&gt;

&lt;p&gt;This is better than creating a lesson made entirely from the weakest character.&lt;/p&gt;

&lt;p&gt;Typing requires transitions between letters, not isolated keypresses.&lt;/p&gt;

&lt;p&gt;For example, a learner struggling with d may benefit from practising combinations such as:&lt;/p&gt;

&lt;p&gt;ad&lt;br&gt;
do&lt;br&gt;
did&lt;br&gt;
red&lt;br&gt;
side&lt;br&gt;
added&lt;/p&gt;

&lt;p&gt;The surrounding letters help train realistic movement patterns.&lt;/p&gt;

&lt;p&gt;Why repeated key errors matter&lt;/p&gt;

&lt;p&gt;Not all mistakes are equally useful.&lt;/p&gt;

&lt;p&gt;A one-off mistake may happen because the learner was distracted.&lt;/p&gt;

&lt;p&gt;A repeated mistake suggests a more stable problem.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;p&gt;Pressing a neighbouring key&lt;br&gt;
Using the wrong finger&lt;br&gt;
Reaching too far&lt;br&gt;
Losing the home-row position&lt;br&gt;
Confusing two similar movements&lt;br&gt;
Typing a familiar letter sequence incorrectly&lt;/p&gt;

&lt;p&gt;A tutor that tracks repeated errors can provide more useful feedback than one that reports only a single overall accuracy percentage.&lt;/p&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;p&gt;Accuracy: 92%&lt;/p&gt;

&lt;p&gt;It can reveal:&lt;/p&gt;

&lt;p&gt;Most difficult keys: R, T, and P&lt;/p&gt;

&lt;p&gt;That gives the learner a clear next step.&lt;/p&gt;

&lt;p&gt;Consistency matters too&lt;/p&gt;

&lt;p&gt;A learner may produce a high average speed through short bursts followed by long pauses.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Fast burst → pause → correction → fast burst → pause&lt;/p&gt;

&lt;p&gt;The average WPM may look respectable, but the rhythm is unstable.&lt;/p&gt;

&lt;p&gt;Consistent typing means maintaining a controlled pace without frequent hesitation or correction.&lt;/p&gt;

&lt;p&gt;This is important because practical typing is not a ten-second sprint.&lt;/p&gt;

&lt;p&gt;Students often need to type:&lt;/p&gt;

&lt;p&gt;Essays&lt;br&gt;
Notes&lt;br&gt;
Assignments&lt;br&gt;
Emails&lt;br&gt;
Code&lt;br&gt;
Research&lt;br&gt;
Exam answers&lt;br&gt;
Long-form documents&lt;/p&gt;

&lt;p&gt;A sustainable rhythm is more useful than a brief personal record.&lt;/p&gt;

&lt;p&gt;Local progress storage&lt;/p&gt;

&lt;p&gt;A typing tutor becomes more useful when it remembers progress between sessions.&lt;/p&gt;

&lt;p&gt;That data may include:&lt;/p&gt;

&lt;p&gt;Active letters&lt;br&gt;
Per-key attempts&lt;br&gt;
First-attempt accuracy&lt;br&gt;
Weak keys&lt;br&gt;
Recent speed&lt;br&gt;
Lesson history&lt;br&gt;
Unlock progress&lt;/p&gt;

&lt;p&gt;The Olivez Typing Tutor stores progress locally on the user’s device.&lt;/p&gt;

&lt;p&gt;This means practice data does not need to be tied to an account or uploaded simply to continue learning.&lt;/p&gt;

&lt;p&gt;Local storage is useful for:&lt;/p&gt;

&lt;p&gt;Quick access&lt;br&gt;
No sign-up requirement&lt;br&gt;
Reduced collection of personal data&lt;br&gt;
Returning to the same practice level later&lt;/p&gt;

&lt;p&gt;Students should remember that locally stored progress is usually connected to the current browser and device.&lt;/p&gt;

&lt;p&gt;Clearing site data, changing browsers, or moving to another device may reset the saved progress.&lt;/p&gt;

&lt;p&gt;A practical typing routine for students&lt;/p&gt;

&lt;p&gt;A productive typing session does not need to be long.&lt;/p&gt;

&lt;p&gt;Fifteen focused minutes can be more useful than an hour of careless repetition.&lt;/p&gt;

&lt;p&gt;Step 1: Begin slowly&lt;/p&gt;

&lt;p&gt;Start at a pace where you can press the correct keys without rushing.&lt;/p&gt;

&lt;p&gt;Avoid chasing WPM during the first few minutes.&lt;/p&gt;

&lt;p&gt;Step 2: Watch first-attempt accuracy&lt;/p&gt;

&lt;p&gt;Notice which keys cause immediate errors.&lt;/p&gt;

&lt;p&gt;Do not treat Backspace as proof that the original movement was correct.&lt;/p&gt;

&lt;p&gt;Step 3: Review weak keys&lt;/p&gt;

&lt;p&gt;Look for repeated patterns.&lt;/p&gt;

&lt;p&gt;Are mistakes concentrated on one hand?&lt;/p&gt;

&lt;p&gt;Do you confuse neighbouring letters?&lt;/p&gt;

&lt;p&gt;Do errors appear more often after particular key combinations?&lt;/p&gt;

&lt;p&gt;Step 4: Practise deliberately&lt;/p&gt;

&lt;p&gt;Keep your fingers near the home row and use the intended finger for each key.&lt;/p&gt;

&lt;p&gt;Typing slowly with correct technique builds movements that can later become fast.&lt;/p&gt;

&lt;p&gt;Step 5: Increase speed gradually&lt;/p&gt;

&lt;p&gt;Once accuracy becomes stable, raise the pace slightly.&lt;/p&gt;

&lt;p&gt;Do not double the target speed in one session.&lt;/p&gt;

&lt;p&gt;Step 6: Stop when technique declines&lt;/p&gt;

&lt;p&gt;Fatigue can produce sloppy movements.&lt;/p&gt;

&lt;p&gt;A shorter session completed carefully is often more valuable than continuing after accuracy falls sharply.&lt;/p&gt;

&lt;p&gt;A student experiment&lt;/p&gt;

&lt;p&gt;Students can compare fixed and adaptive practice using a simple experiment.&lt;/p&gt;

&lt;p&gt;Phase 1: Baseline test&lt;/p&gt;

&lt;p&gt;Complete a normal typing test and record:&lt;/p&gt;

&lt;p&gt;WPM&lt;br&gt;
Final accuracy&lt;br&gt;
First-attempt accuracy&lt;br&gt;
Most difficult keys&lt;br&gt;
Phase 2: Targeted practice&lt;/p&gt;

&lt;p&gt;Spend several sessions practising lessons that include the weakest keys more frequently.&lt;/p&gt;

&lt;p&gt;Phase 3: Retest&lt;/p&gt;

&lt;p&gt;Repeat a similar typing test and compare the results.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;p&gt;Did first-attempt accuracy improve?&lt;br&gt;
Did the same keys remain difficult?&lt;br&gt;
Did corrections decrease?&lt;br&gt;
Did speed improve without reducing accuracy?&lt;br&gt;
Did typing rhythm become steadier?&lt;/p&gt;

&lt;p&gt;This turns typing practice into a measurable learning exercise rather than repeated guessing.&lt;/p&gt;

&lt;p&gt;Common mistakes when learning touch typing&lt;br&gt;
Looking at the keyboard constantly&lt;/p&gt;

&lt;p&gt;Looking down may help find a key immediately, but it slows the development of keyboard memory.&lt;/p&gt;

&lt;p&gt;Use the screen as the main reference and look down only when necessary.&lt;/p&gt;

&lt;p&gt;Chasing speed too early&lt;/p&gt;

&lt;p&gt;Fast incorrect movements are still incorrect movements.&lt;/p&gt;

&lt;p&gt;Build accuracy first.&lt;/p&gt;

&lt;p&gt;Using the wrong finger repeatedly&lt;/p&gt;

&lt;p&gt;A learner may reach a reasonable speed using improvised finger movements, but those habits can create limits later.&lt;/p&gt;

&lt;p&gt;Consistent fingering reduces unnecessary movement.&lt;/p&gt;

&lt;p&gt;Ignoring weak keys&lt;/p&gt;

&lt;p&gt;Repeating easy passages can feel satisfying because the score stays high.&lt;/p&gt;

&lt;p&gt;Improvement usually requires spending more time on uncomfortable movements.&lt;/p&gt;

&lt;p&gt;Practising for too long&lt;/p&gt;

&lt;p&gt;Extended sessions can cause fatigue and reduced concentration.&lt;/p&gt;

&lt;p&gt;Short, regular sessions are easier to maintain.&lt;/p&gt;

&lt;p&gt;Try the Olivez Typing Tutor&lt;/p&gt;

&lt;p&gt;The Olivez Typing Tutor is designed around adaptive practice rather than fixed repetition.&lt;/p&gt;

&lt;p&gt;It tracks first-attempt performance, identifies difficult keys, adjusts lessons, and introduces new letters progressively.&lt;/p&gt;

&lt;p&gt;You can use it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olivez.in/tool/typing-tutor" rel="noopener noreferrer"&gt;https://olivez.in/tool/typing-tutor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No account is required, and progress is stored locally on the device.&lt;/p&gt;

&lt;p&gt;The goal is not simply to produce the highest WPM score possible.&lt;/p&gt;

&lt;p&gt;The goal is to build accurate, reliable typing movements that remain stable as speed increases.&lt;/p&gt;

&lt;p&gt;A good typing tutor should not only tell you how you performed.&lt;/p&gt;

&lt;p&gt;It should help decide what you need to practise next.&lt;/p&gt;

&lt;p&gt;What affects your typing most: speed, repeated key errors, or maintaining a consistent rhythm?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How a Fair Online Dice Roller Works: Probability, Randomness, and Classroom Experiments</title>
      <dc:creator>Kaifi Azam</dc:creator>
      <pubDate>Tue, 04 Aug 2026 10:18:21 +0000</pubDate>
      <link>https://dev.to/kaifi_azam_21/how-a-fair-online-dice-roller-works-probability-randomness-and-classroom-experiments-479f</link>
      <guid>https://dev.to/kaifi_azam_21/how-a-fair-online-dice-roller-works-probability-randomness-and-classroom-experiments-479f</guid>
      <description>&lt;p&gt;Rolling a die looks simple.&lt;/p&gt;

&lt;p&gt;You click a button, watch the die move, and receive a number from 1 to 6.&lt;/p&gt;

&lt;p&gt;Behind a reliable online dice roller, however, there are several interesting ideas involving probability, randomness, software design, and fairness.&lt;/p&gt;

&lt;p&gt;These ideas make dice rolling a useful starting point for students learning mathematics or programming.&lt;/p&gt;

&lt;p&gt;In this article, we will explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How dice probabilities work&lt;/li&gt;
&lt;li&gt;Why short sequences can look unfair&lt;/li&gt;
&lt;li&gt;Why rolling two dice changes the distribution&lt;/li&gt;
&lt;li&gt;How software generates random results&lt;/li&gt;
&lt;li&gt;How students can run their own probability experiments&lt;/li&gt;
&lt;li&gt;How the Olivez Dice Roller handles random rolls&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The probability of rolling one die
&lt;/h2&gt;

&lt;p&gt;A standard six-sided die has six possible outcomes:&lt;/p&gt;

&lt;p&gt;1, 2, 3, 4, 5, and 6&lt;/p&gt;

&lt;p&gt;When the die is fair, each face has the same theoretical probability.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
P(\text{specific number}) = \frac{1}{6}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;That is approximately:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
16.67%&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;This means the probability of rolling a 4 is exactly the same as the probability of rolling a 1.&lt;/p&gt;

&lt;p&gt;However, this does not mean every group of six rolls will contain each number exactly once.&lt;/p&gt;

&lt;p&gt;A sequence such as this is completely possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3, 3, 6, 1, 3, 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The number 3 appeared three times, while 2 and 4 did not appear at all.&lt;/p&gt;

&lt;p&gt;That does not prove the die is unfair. Probability describes what we expect over many trials, not what must happen in every short sequence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Randomness often looks less balanced than expected
&lt;/h2&gt;

&lt;p&gt;People naturally look for patterns.&lt;/p&gt;

&lt;p&gt;When the same number appears repeatedly, it can feel suspicious. When a number has not appeared recently, it can feel as though it is “due.”&lt;/p&gt;

&lt;p&gt;Neither idea changes the next independent roll.&lt;/p&gt;

&lt;p&gt;Suppose a die produces five consecutive sixes. The probability that the next roll is also a six remains:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\frac{1}{6}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;The die does not remember its previous results.&lt;/p&gt;

&lt;p&gt;This is an example of independence. Each roll begins with the same set of possible outcomes and the same probability for each face.&lt;/p&gt;

&lt;p&gt;The belief that a missing result becomes more likely is often called the gambler’s fallacy.&lt;/p&gt;
&lt;h2&gt;
  
  
  What changes when you roll two dice?
&lt;/h2&gt;

&lt;p&gt;Rolling two dice creates 36 ordered combinations.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(1, 1)
(1, 2)
(1, 3)
...
(6, 5)
(6, 6)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although each individual combination has the same probability, the totals do not.&lt;/p&gt;

&lt;p&gt;A total of 2 has only one possible combination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A total of 7 has six possible combinations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 + 6
2 + 5
3 + 4
4 + 3
5 + 2
6 + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes 7 the most likely total when rolling two standard dice.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;th&gt;Number of combinations&lt;/th&gt;
&lt;th&gt;Probability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2/36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1/36&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This distribution explains why totals near the middle appear more frequently than totals near the edges.&lt;/p&gt;

&lt;p&gt;It also gives students a clear way to compare theoretical probability with experimental results.&lt;/p&gt;

&lt;h2&gt;
  
  
  How an online dice roller generates results
&lt;/h2&gt;

&lt;p&gt;A physical die relies on motion, gravity, surface shape, and collisions.&lt;/p&gt;

&lt;p&gt;An online dice roller needs a source of random values from the computer.&lt;/p&gt;

&lt;p&gt;A basic implementation might use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is convenient for simple demonstrations, but &lt;code&gt;Math.random()&lt;/code&gt; is not intended for situations where stronger and less predictable randomness is preferred.&lt;/p&gt;

&lt;p&gt;The Olivez Dice Roller uses the browser’s secure random-value API instead.&lt;/p&gt;

&lt;p&gt;A simplified version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces a random unsigned 32-bit integer.&lt;/p&gt;

&lt;p&gt;The application must then convert that large integer into one of six possible dice values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why directly using the remainder can introduce bias
&lt;/h2&gt;

&lt;p&gt;A tempting approach is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;randomNumber&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remainder operator maps numbers into the range 0 to 5.&lt;/p&gt;

&lt;p&gt;The problem is that the number of possible 32-bit values is not perfectly divisible by 6.&lt;/p&gt;

&lt;p&gt;That means some remainders could receive one additional possible source value.&lt;/p&gt;

&lt;p&gt;The difference is extremely small, but a carefully designed dice roller can avoid it entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using rejection sampling for even mapping
&lt;/h2&gt;

&lt;p&gt;Rejection sampling solves the problem by ignoring values from the small uneven section at the top of the range.&lt;/p&gt;

&lt;p&gt;The process is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a random integer.&lt;/li&gt;
&lt;li&gt;Check whether it falls inside the largest range evenly divisible by 6.&lt;/li&gt;
&lt;li&gt;Reject it if it falls outside that range.&lt;/li&gt;
&lt;li&gt;Map the accepted value to a die face.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simplified example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rollDie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every final face receives the same number of accepted input values.&lt;/p&gt;

&lt;p&gt;This is more careful than a dice roller strictly needs for casual classroom use, but it makes the mapping mathematically even.&lt;/p&gt;

&lt;h2&gt;
  
  
  The animation does not choose the result
&lt;/h2&gt;

&lt;p&gt;A common misunderstanding is that the visible dice animation determines where the die lands.&lt;/p&gt;

&lt;p&gt;In the Olivez Dice Roller, the result is generated by the random-number logic. The animation simply communicates that a new roll is taking place.&lt;/p&gt;

&lt;p&gt;Separating the result from the visual effect has several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced motion settings can be respected&lt;/li&gt;
&lt;li&gt;The result does not depend on frame rate&lt;/li&gt;
&lt;li&gt;Slower devices do not produce different probabilities&lt;/li&gt;
&lt;li&gt;The interface remains predictable and accessible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The visual design makes the roll easier to follow, while the random-generation system determines the actual value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Probability experiment for students
&lt;/h2&gt;

&lt;p&gt;Students can use an online dice roller to compare theory with real results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Experiment 1: Roll one die 60 times
&lt;/h3&gt;

&lt;p&gt;Create a table with one row for each face.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Face&lt;/th&gt;
&lt;th&gt;Expected count&lt;/th&gt;
&lt;th&gt;Observed count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The expected count is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
60 \times \frac{1}{6} = 10&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;The observed values will probably not be exactly 10 for every face.&lt;/p&gt;

&lt;p&gt;Students can then calculate the experimental probability:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
P(\text{face}) = \frac{\text{number of times the face appeared}}{\text{total rolls}}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Increasing the experiment from 60 rolls to 600 rolls will usually produce proportions closer to the theoretical probability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Experiment 2: Roll two dice 100 times
&lt;/h3&gt;

&lt;p&gt;Record the total from each roll.&lt;/p&gt;

&lt;p&gt;Students should expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;7 to appear frequently&lt;/li&gt;
&lt;li&gt;6 and 8 to appear slightly less frequently&lt;/li&gt;
&lt;li&gt;2 and 12 to appear rarely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact results will vary, but the overall shape should begin to resemble the theoretical distribution as the number of trials increases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Experiment 3: Test a prediction
&lt;/h3&gt;

&lt;p&gt;Before rolling, ask students to predict:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which total will appear most often?&lt;/li&gt;
&lt;li&gt;Will 2 or 12 appear first?&lt;/li&gt;
&lt;li&gt;How many rolls will be needed before every total appears?&lt;/li&gt;
&lt;li&gt;Can the same total occur five times consecutively?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The purpose is not merely to guess correctly. It is to compare intuition with evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful applications beyond probability lessons
&lt;/h2&gt;

&lt;p&gt;An online dice roller can also support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Board games when physical dice are unavailable&lt;/li&gt;
&lt;li&gt;Classroom turn-taking activities&lt;/li&gt;
&lt;li&gt;Creative writing prompts&lt;/li&gt;
&lt;li&gt;Random decision exercises&lt;/li&gt;
&lt;li&gt;Game design testing&lt;/li&gt;
&lt;li&gt;Statistics demonstrations&lt;/li&gt;
&lt;li&gt;Coding lessons involving arrays, loops, and frequency counts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Olivez Dice Roller supports between 1 and 10 six-sided dice.&lt;/p&gt;

&lt;p&gt;It also includes keyboard controls and a fullscreen view, making it practical for classroom displays, projectors, shared screens, and group activities.&lt;/p&gt;

&lt;p&gt;The rolls are generated locally on the user’s device. There is no account requirement and no roll history needs to be uploaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the Olivez Dice Roller
&lt;/h2&gt;

&lt;p&gt;You can use the tool here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olivez.in/tool/dice-roller" rel="noopener noreferrer"&gt;https://olivez.in/tool/dice-roller&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose how many dice you need, roll them, and compare the results with your probability predictions.&lt;/p&gt;

&lt;p&gt;A dice roller may be a small tool, but it provides a useful introduction to several larger ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Theoretical and experimental probability&lt;/li&gt;
&lt;li&gt;Independent events&lt;/li&gt;
&lt;li&gt;Random-number generation&lt;/li&gt;
&lt;li&gt;Distribution patterns&lt;/li&gt;
&lt;li&gt;Fair value mapping&lt;/li&gt;
&lt;li&gt;Accessible interface design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes the simplest tools provide the clearest way to understand difficult concepts.&lt;/p&gt;

&lt;p&gt;What result do you think would appear most often if you rolled three dice 1,000 times?&lt;/p&gt;

&lt;h1&gt;
  
  
  javascript #webdev #education #probability
&lt;/h1&gt;

</description>
      <category>beginners</category>
      <category>computerscience</category>
      <category>learning</category>
      <category>science</category>
    </item>
    <item>
      <title>How to Calculate an IPv4 Subnet Range From Any IP Address</title>
      <dc:creator>Kaifi Azam</dc:creator>
      <pubDate>Fri, 31 Jul 2026 21:42:35 +0000</pubDate>
      <link>https://dev.to/kaifi_azam_21/how-to-calculate-an-ipv4-subnet-range-from-any-ip-address-1518</link>
      <guid>https://dev.to/kaifi_azam_21/how-to-calculate-an-ipv4-subnet-range-from-any-ip-address-1518</guid>
      <description>&lt;h1&gt;
  
  
  How to Calculate an IPv4 Subnet Range From Any IP Address
&lt;/h1&gt;

&lt;p&gt;A CIDR value such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.130/26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;contains two pieces of information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;192.168.1.130&lt;/code&gt; is an address inside the subnet&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/26&lt;/code&gt; means the first 26 bits identify the network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entered address does not need to be the network address. You can calculate the containing network from any valid address inside the range.&lt;/p&gt;

&lt;p&gt;In this example, the result is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network:          192.168.1.128/26
Broadcast:        192.168.1.191
First usable:     192.168.1.129
Last usable:      192.168.1.190
Subnet mask:      255.255.255.192
Wildcard mask:    0.0.0.63
Total addresses:  64
Usable hosts:     62
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how to calculate every value manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Convert the prefix into host bits
&lt;/h2&gt;

&lt;p&gt;IPv4 addresses contain 32 bits.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;/26&lt;/code&gt; prefix reserves 26 bits for the network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host bits = 32 - 26
Host bits = 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The subnet therefore contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2⁶ = 64 addresses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a normal subnet, the lowest address identifies the network and the highest address is the broadcast address.&lt;/p&gt;

&lt;p&gt;That leaves:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;64 - 2 = 62 usable host addresses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Find the subnet mask
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;/26&lt;/code&gt; mask contains 26 ones followed by 6 zeros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11111111.11111111.11111111.11000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Convert each octet to decimal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;255.255.255.192
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the subnet mask is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;255.255.255.192
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Calculate the block size
&lt;/h2&gt;

&lt;p&gt;The interesting octet is the first mask octet that is not &lt;code&gt;255&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;/26&lt;/code&gt;, that octet is &lt;code&gt;192&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Calculate the block size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Block size = 256 - 192
Block size = 64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The possible subnet boundaries in the final octet are therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0
64
128
192
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each range contains 64 addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0–63
64–127
128–191
192–255
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entered address ends in &lt;code&gt;130&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;130&lt;/code&gt; falls between &lt;code&gt;128&lt;/code&gt; and &lt;code&gt;191&lt;/code&gt;, its network is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.128/26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Find the broadcast address
&lt;/h2&gt;

&lt;p&gt;The broadcast address is the final address in the subnet.&lt;/p&gt;

&lt;p&gt;The selected block runs from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.128
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.191
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broadcast address = 192.168.1.191
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another way to calculate it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broadcast = Network + Total addresses - 1
Broadcast = 128 + 64 - 1
Broadcast = 191
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Find the usable host range
&lt;/h2&gt;

&lt;p&gt;For a traditional IPv4 subnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First usable = Network + 1
Last usable  = Broadcast - 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First usable: 192.168.1.129
Last usable:  192.168.1.190
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The same calculation in binary
&lt;/h2&gt;

&lt;p&gt;The final octet of the entered IP is &lt;code&gt;130&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;130 = 10000010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final octet of the &lt;code&gt;/26&lt;/code&gt; mask is &lt;code&gt;192&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192 = 11000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the mask to the address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IP:       10000010
Mask:     11000000
Network:  10000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;10000000&lt;/code&gt; is &lt;code&gt;128&lt;/code&gt;, giving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.128
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set all six host bits to &lt;code&gt;1&lt;/code&gt; to find the broadcast address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network:    10000000
Broadcast:  10111111
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;10111111&lt;/code&gt; is &lt;code&gt;191&lt;/code&gt;, giving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.191
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick CIDR reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Subnet mask&lt;/th&gt;
&lt;th&gt;Total addresses&lt;/th&gt;
&lt;th&gt;Traditional usable hosts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;td&gt;254&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/25&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.128&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;126&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.192&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/27&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.224&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.240&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/29&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.248&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.252&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/31&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.254&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Special case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.255&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Single address&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same block-size method works across octet boundaries.&lt;/p&gt;

&lt;p&gt;For example, with a &lt;code&gt;/20&lt;/code&gt; mask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subnet mask = 255.255.240.0
Block size  = 256 - 240
Block size  = 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The third-octet boundaries are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0, 16, 32, 48, 64, 80...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An address such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;172.16.37.10/20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;falls inside the &lt;code&gt;32–47&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Its containing network is therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;172.16.32.0/20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and its broadcast address is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;172.16.47.255
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;code&gt;/31&lt;/code&gt; exception
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;/31&lt;/code&gt; contains two addresses.&lt;/p&gt;

&lt;p&gt;Under the traditional subnet rule, subtracting a network and broadcast address would leave no usable hosts. However, &lt;code&gt;/31&lt;/code&gt; networks can use both addresses as endpoints on a point-to-point link.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.0.0.4/31
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.0.0.4
10.0.0.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On an appropriately configured point-to-point link, both can be used as endpoint addresses.&lt;/p&gt;

&lt;p&gt;Do not automatically treat &lt;code&gt;/31&lt;/code&gt; like a regular LAN subnet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does &lt;code&gt;/32&lt;/code&gt; mean?
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;/32&lt;/code&gt; identifies one exact IPv4 address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;203.0.113.25/32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It contains no additional addresses and is commonly used when a route, rule, or configuration must match a single host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculate and verify it automatically
&lt;/h2&gt;

&lt;p&gt;For quick checks, I built the &lt;a href="https://olivez.in/tool/subnet-calculator" rel="noopener noreferrer"&gt;Olivez IPv4 Subnet Calculator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can enter any IPv4 address with a prefix from &lt;code&gt;/0&lt;/code&gt; through &lt;code&gt;/32&lt;/code&gt;, including an address that is not already the network boundary.&lt;/p&gt;

&lt;p&gt;It calculates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Containing CIDR network&lt;/li&gt;
&lt;li&gt;Subnet mask&lt;/li&gt;
&lt;li&gt;Wildcard mask&lt;/li&gt;
&lt;li&gt;Broadcast address&lt;/li&gt;
&lt;li&gt;First and last usable addresses&lt;/li&gt;
&lt;li&gt;Total and usable address counts&lt;/li&gt;
&lt;li&gt;Address classification&lt;/li&gt;
&lt;li&gt;Binary network and host split&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, entering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.130/26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returns the normalized network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.128/26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The calculator is useful for verifying manual work, but understanding the block-size method makes it much easier to spot incorrect CIDR ranges in routing tables, firewall rules, cloud networks, and infrastructure configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  A reusable calculation process
&lt;/h2&gt;

&lt;p&gt;For any IPv4 address and prefix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Subtract the prefix from 32 to find the number of host bits.&lt;/li&gt;
&lt;li&gt;Calculate &lt;code&gt;2^host bits&lt;/code&gt; to find the total number of addresses.&lt;/li&gt;
&lt;li&gt;Convert the prefix to a subnet mask.&lt;/li&gt;
&lt;li&gt;Find the first mask octet that is not &lt;code&gt;255&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Calculate its block size using &lt;code&gt;256 - mask octet&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Find which block contains the entered address.&lt;/li&gt;
&lt;li&gt;Use the first address as the network boundary.&lt;/li&gt;
&lt;li&gt;Use the final address as the broadcast boundary.&lt;/li&gt;
&lt;li&gt;Exclude those two addresses for the traditional usable range.&lt;/li&gt;
&lt;li&gt;Handle &lt;code&gt;/31&lt;/code&gt; and &lt;code&gt;/32&lt;/code&gt; as special cases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you can identify the block boundary, the rest of the subnet becomes straightforward.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Verify a SHA-256 Checksum on Windows, macOS, and Linux</title>
      <dc:creator>Kaifi Azam</dc:creator>
      <pubDate>Fri, 31 Jul 2026 21:34:52 +0000</pubDate>
      <link>https://dev.to/kaifi_azam_21/how-to-verify-a-sha-256-checksum-on-windows-macos-and-linux-347i</link>
      <guid>https://dev.to/kaifi_azam_21/how-to-verify-a-sha-256-checksum-on-windows-macos-and-linux-347i</guid>
      <description>&lt;h1&gt;
  
  
  How to Verify a SHA-256 Checksum on Windows, macOS, and Linux
&lt;/h1&gt;

&lt;p&gt;You download an ISO, installer, archive, or release binary. The publisher provides a long value such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9f86d081884c7d659a2feaa0c55ad015
a3bf4f1b2b0b822cd15d6c15b0f00a08
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That value is a checksum, usually generated with SHA-256.&lt;/p&gt;

&lt;p&gt;Verifying it answers one practical question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the file you downloaded have exactly the same contents as the file the publisher hashed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A checksum mismatch can indicate a damaged download, an incomplete transfer, the wrong file version, or modified contents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before verifying anything
&lt;/h2&gt;

&lt;p&gt;Get the expected checksum from a source you trust.&lt;/p&gt;

&lt;p&gt;Ideally, use the software publisher’s official website, release page, package repository, or signed checksum file.&lt;/p&gt;

&lt;p&gt;A matching checksum confirms that your file matches the data represented by the expected hash. It does not prove that the original publisher or website was trustworthy. If an attacker can replace both the download and the displayed checksum, they can make the two values match.&lt;/p&gt;

&lt;p&gt;For stronger authenticity verification, use a signed release when the publisher provides one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify SHA-256 on Windows
&lt;/h2&gt;

&lt;p&gt;Open PowerShell in the folder containing the downloaded file.&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-FileHash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".\filename.iso"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Algorithm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SHA256&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-FileHash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".\ubuntu.iso"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Algorithm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SHA256&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell returns something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Algorithm : SHA256
Hash      : 4A1F...
Path      : C:\Users\You\Downloads\ubuntu.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the value beside &lt;code&gt;Hash&lt;/code&gt; with the checksum published by the download provider.&lt;/p&gt;

&lt;p&gt;Uppercase and lowercase letters do not matter in hexadecimal hashes. The characters themselves must otherwise match exactly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compare automatically in PowerShell
&lt;/h3&gt;

&lt;p&gt;Instead of comparing two 64-character values manually, store the expected checksum and let PowerShell compare them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PASTE_EXPECTED_SHA256_HERE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$actual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-FileHash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".\filename.iso"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Algorithm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$actual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Checksum matches"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Checksum does not match"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verify SHA-256 on macOS
&lt;/h2&gt;

&lt;p&gt;Open Terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 filename.dmg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 application.dmg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result contains the calculated checksum followed by the filename:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4a1f...  application.dmg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the calculated value with the publisher’s expected SHA-256 checksum.&lt;/p&gt;

&lt;p&gt;Quotes are useful when a filename contains spaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 &lt;span class="s2"&gt;"Application Installer.dmg"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verify SHA-256 on Linux
&lt;/h2&gt;

&lt;p&gt;Most Linux distributions provide &lt;code&gt;sha256sum&lt;/code&gt; through GNU core utilities.&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum &lt;/span&gt;filename.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum &lt;/span&gt;linux-distribution.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4a1f...  linux-distribution.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the first value with the checksum from the publisher.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify a SHA256SUMS file on Linux
&lt;/h2&gt;

&lt;p&gt;Some projects provide a file named &lt;code&gt;SHA256SUMS&lt;/code&gt;, &lt;code&gt;checksums.txt&lt;/code&gt;, or something similar.&lt;/p&gt;

&lt;p&gt;A GNU checksum line normally looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4a1f...  linux-distribution.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the checksum file and downloaded file are in the same directory, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;--check&lt;/span&gt; SHA256SUMS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The short form also works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; SHA256SUMS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful result looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;linux-distribution.iso: OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failure may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;linux-distribution.iso: FAILED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is safer than visually comparing long values because the command performs the comparison directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify a checksum without using the command line
&lt;/h2&gt;

&lt;p&gt;For occasional checks, I built the &lt;a href="https://olivez.in/tool/hash-generator-checker" rel="noopener noreferrer"&gt;Olivez Hash Generator &amp;amp; Checksum Checker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It supports SHA-256, SHA-384, and SHA-512 for files and exact text.&lt;/p&gt;

&lt;p&gt;The verification field accepts several common formats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4a1f...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4a1f...  filename.iso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SHA256 (filename.iso) = 4a1f...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SHA-256: 4a1f...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can also read multiline checksum lists and select the entry matching the chosen filename.&lt;/p&gt;

&lt;p&gt;Files and text are processed locally and are not uploaded. The current file limit is 100 MB, so command-line tools remain the better option for large ISO images and multi-gigabyte archives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did my checksum fail?
&lt;/h2&gt;

&lt;p&gt;A mismatch does not automatically mean malware. Common causes include:&lt;/p&gt;

&lt;h3&gt;
  
  
  You downloaded a different version
&lt;/h3&gt;

&lt;p&gt;Checksums change whenever file contents change. Version 2.1 and version 2.1.1 will normally have completely different hashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The download was incomplete or corrupted
&lt;/h3&gt;

&lt;p&gt;Delete the file, download it again, and recalculate the checksum.&lt;/p&gt;

&lt;h3&gt;
  
  
  You selected the wrong algorithm
&lt;/h3&gt;

&lt;p&gt;A SHA-256 value contains 64 hexadecimal characters.&lt;/p&gt;

&lt;p&gt;Common digest lengths are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Hexadecimal characters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MD5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-256&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-384&lt;/td&gt;
&lt;td&gt;96&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-512&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Calculating SHA-512 will never match a published SHA-256 value, even when both were generated from the same file.&lt;/p&gt;

&lt;h3&gt;
  
  
  The checksum belongs to another filename
&lt;/h3&gt;

&lt;p&gt;Checksum lists often contain values for several operating systems, architectures, or package formats. Confirm that you are comparing the entry for the exact file you downloaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  The expected value contains extra text
&lt;/h3&gt;

&lt;p&gt;Publishers may use GNU, BSD, labelled, or custom checksum formats. Make sure you are comparing the digest itself rather than copying punctuation, a filename, or the algorithm label into a field that expects only hexadecimal characters.&lt;/p&gt;

&lt;h2&gt;
  
  
  SHA-256 is not password hashing
&lt;/h2&gt;

&lt;p&gt;SHA-256 is useful for file integrity, release verification, content identification, and similar tasks.&lt;/p&gt;

&lt;p&gt;Do not store passwords as plain SHA-256 hashes.&lt;/p&gt;

&lt;p&gt;Password storage requires a dedicated password-hashing function such as Argon2id, scrypt, bcrypt, or PBKDF2 with appropriate parameters and unique salts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical rule
&lt;/h2&gt;

&lt;p&gt;Use the operating system command when you regularly verify files or work with large downloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows: Get-FileHash
macOS:   shasum -a 256
Linux:   sha256sum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a local-processing interface when you need to check a smaller file, compare text, parse a complete checksum line, or inspect a multiline checksum list without manually extracting the correct digest.&lt;/p&gt;

&lt;p&gt;Whichever method you use, obtain the expected checksum from a trusted source and make sure the algorithm, filename, and file version all match.&lt;/p&gt;

</description>
      <category>security</category>
      <category>tutorial</category>
      <category>linux</category>
      <category>android</category>
    </item>
    <item>
      <title>How to Convert Nested JSON to CSV Without Losing Fields</title>
      <dc:creator>Kaifi Azam</dc:creator>
      <pubDate>Fri, 31 Jul 2026 20:22:35 +0000</pubDate>
      <link>https://dev.to/kaifi_azam_21/how-to-convert-nested-json-to-csv-without-losing-fields-1ac1</link>
      <guid>https://dev.to/kaifi_azam_21/how-to-convert-nested-json-to-csv-without-losing-fields-1ac1</guid>
      <description>&lt;p&gt;Converting a flat JSON array to CSV is straightforward. Real datasets are rarely flat.&lt;/p&gt;

&lt;p&gt;API responses often contain nested objects, arrays, optional fields, large numeric identifiers, and properties that appear only in later records. A basic conversion can silently drop data, misalign columns, or change values when the CSV is opened in spreadsheet software.&lt;/p&gt;

&lt;p&gt;This guide covers the main problems and how to handle them safely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq3mq9j7ruhv2xt1r749i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq3mq9j7ruhv2xt1r749i.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The converted table can be reviewed and adjusted before exporting CSV or XLSX.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple JSON to CSV conversion
&lt;/h2&gt;

&lt;p&gt;This JSON is already tabular:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ada"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Engineer"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Linus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Developer"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It maps cleanly to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name,role
Ada,Engineer
Linus,Developer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each object becomes a row, and each property becomes a column.&lt;/p&gt;

&lt;p&gt;The problems begin when the structure becomes more complex.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Flatten nested objects
&lt;/h2&gt;

&lt;p&gt;Consider this dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ada"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Analytical Systems"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UK"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CSV does not support nested objects directly. One practical solution is to flatten nested fields using dot notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id,name,company.name,company.country
101,Ada,Analytical Systems,UK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This preserves the original field relationships without storing the complete object as an unreadable JSON string.&lt;/p&gt;

&lt;p&gt;For deeper structures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"London"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting column can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customer.address.city
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flattening rule should remain predictable throughout the dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Handle arrays consistently
&lt;/h2&gt;

&lt;p&gt;Arrays may contain primitive values, objects, different numbers of items, or mixed structures.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ada"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"JavaScript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Python"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Linus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One approach is to expand array positions into numbered columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name,skills__001,skills__002
Ada,JavaScript,Python
Linus,C,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second row keeps an empty &lt;code&gt;skills__002&lt;/code&gt; cell instead of shifting data into the wrong column.&lt;/p&gt;

&lt;p&gt;Arrays of objects can follow the same pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible columns include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orders__001.id
orders__001.total
orders__002.id
orders__002.total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may not be the ideal structure for every analysis workflow, but it creates stable columns without discarding values.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Scan every record for columns
&lt;/h2&gt;

&lt;p&gt;A common conversion mistake is using only the first object to determine the CSV headers.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ada"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Linus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linus@example.com"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using only the first object would produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id,name
1,Ada
2,Linus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;email&lt;/code&gt; field disappears.&lt;/p&gt;

&lt;p&gt;A safer converter scans the complete dataset and creates a union of every discovered field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id,name,email
1,Ada,
2,Linus,linus@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Missing values become empty cells while every row remains correctly aligned.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Preserve large numeric identifiers
&lt;/h2&gt;

&lt;p&gt;JavaScript cannot safely represent every large integer as a normal number.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9223372036854775807&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That value exceeds JavaScript's safe integer range. Parsing it normally may change the final digits.&lt;/p&gt;

&lt;p&gt;This matters for values such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database IDs&lt;/li&gt;
&lt;li&gt;Order numbers&lt;/li&gt;
&lt;li&gt;Social media identifiers&lt;/li&gt;
&lt;li&gt;Financial reference numbers&lt;/li&gt;
&lt;li&gt;Snowflake-style IDs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Large identifiers should be preserved as text rather than silently rounded.&lt;/p&gt;

&lt;p&gt;Spreadsheet software may also display long identifiers using scientific notation, so treating them as strings is often safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Support JSONL and NDJSON
&lt;/h2&gt;

&lt;p&gt;Not every dataset is stored as one JSON array.&lt;/p&gt;

&lt;p&gt;JSON Lines and NDJSON store one complete JSON object on each line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Ada"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Linus"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Grace"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This format is common in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log exports&lt;/li&gt;
&lt;li&gt;Streaming systems&lt;/li&gt;
&lt;li&gt;Data pipelines&lt;/li&gt;
&lt;li&gt;Large datasets&lt;/li&gt;
&lt;li&gt;Command-line workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A useful converter should recognize both standard JSON arrays and line-delimited JSON.&lt;/p&gt;

&lt;p&gt;Each valid line becomes one table row.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Escape CSV values correctly
&lt;/h2&gt;

&lt;p&gt;CSV values need escaping when they contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commas&lt;/li&gt;
&lt;li&gt;Quotation marks&lt;/li&gt;
&lt;li&gt;New lines&lt;/li&gt;
&lt;li&gt;The selected delimiter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A value such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;London, United Kingdom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Must be exported as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"London, United Kingdom"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quotation marks inside a quoted value must be doubled.&lt;/p&gt;

&lt;p&gt;This value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;She said "hello"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"She said ""hello"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without correct escaping, columns may become misaligned when the file is opened.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Protect against spreadsheet formulas
&lt;/h2&gt;

&lt;p&gt;Spreadsheet software may interpret cells beginning with certain characters as formulas.&lt;/p&gt;

&lt;p&gt;Potential examples include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=SUM(A1:A5)
+CMD
-10+20
@IMPORTXML(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is commonly called CSV or spreadsheet formula injection.&lt;/p&gt;

&lt;p&gt;A safer CSV export can prefix suspicious values so the spreadsheet treats them as text instead of executing them as formulas.&lt;/p&gt;

&lt;p&gt;This is especially important when the original JSON contains values from users, forms, APIs, or external systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Preview the table before exporting
&lt;/h2&gt;

&lt;p&gt;A table preview helps reveal structural problems before creating the final file.&lt;/p&gt;

&lt;p&gt;Useful checks include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Were nested fields flattened correctly?&lt;/li&gt;
&lt;li&gt;Did later records introduce additional columns?&lt;/li&gt;
&lt;li&gt;Are arrays expanding consistently?&lt;/li&gt;
&lt;li&gt;Are large identifiers unchanged?&lt;/li&gt;
&lt;li&gt;Are unexpected fields present?&lt;/li&gt;
&lt;li&gt;Are some columns mostly empty?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Column selection is also useful when an API response contains dozens of fields but only a few are needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Choose CSV or XLSX based on the workflow
&lt;/h2&gt;

&lt;p&gt;CSV is usually better when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file will be imported into another system&lt;/li&gt;
&lt;li&gt;Portability matters&lt;/li&gt;
&lt;li&gt;A simple text format is preferred&lt;/li&gt;
&lt;li&gt;The dataset will be processed by code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;XLSX can be more convenient when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file will be opened directly in spreadsheet software&lt;/li&gt;
&lt;li&gt;Users expect a native spreadsheet file&lt;/li&gt;
&lt;li&gt;Long identifiers need more controlled handling&lt;/li&gt;
&lt;li&gt;A structured workbook is preferred&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The correct format depends on what will happen after conversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical checklist
&lt;/h2&gt;

&lt;p&gt;Before exporting JSON data, confirm that the converter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scans every record for fields&lt;/li&gt;
&lt;li&gt;Flattens nested objects predictably&lt;/li&gt;
&lt;li&gt;Handles arrays without shifting columns&lt;/li&gt;
&lt;li&gt;Keeps missing values aligned&lt;/li&gt;
&lt;li&gt;Preserves large integer identifiers&lt;/li&gt;
&lt;li&gt;Escapes delimiters, quotation marks, and new lines&lt;/li&gt;
&lt;li&gt;Protects against spreadsheet formulas&lt;/li&gt;
&lt;li&gt;Supports JSONL and NDJSON when needed&lt;/li&gt;
&lt;li&gt;Provides a preview before downloading&lt;/li&gt;
&lt;li&gt;Lets users remove unnecessary columns&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A converter built for these cases
&lt;/h2&gt;

&lt;p&gt;I built Olivez JSON to CSV Converter while working through these problems.&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON, JSONL, and NDJSON&lt;/li&gt;
&lt;li&gt;Pasted data&lt;/li&gt;
&lt;li&gt;Local files up to 100 MB&lt;/li&gt;
&lt;li&gt;Public JSON URLs&lt;/li&gt;
&lt;li&gt;Nested object flattening&lt;/li&gt;
&lt;li&gt;Stable numbered array columns&lt;/li&gt;
&lt;li&gt;Full-dataset column discovery&lt;/li&gt;
&lt;li&gt;Large integer preservation&lt;/li&gt;
&lt;li&gt;Table preview and column selection&lt;/li&gt;
&lt;li&gt;CSV and XLSX export&lt;/li&gt;
&lt;li&gt;Custom CSV delimiters&lt;/li&gt;
&lt;li&gt;Spreadsheet formula protection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Local files and pasted data are processed on your device, and no account is required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olivez.in/tool/json-to-csv-converter" rel="noopener noreferrer"&gt;https://olivez.in/tool/json-to-csv-converter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal was not only to replace braces with commas. It was to make the conversion predictable enough that you can inspect the result and trust the exported file.&lt;/p&gt;

</description>
      <category>json</category>
      <category>webdev</category>
      <category>data</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>This is my fav design for a web!</title>
      <dc:creator>Kaifi Azam</dc:creator>
      <pubDate>Fri, 31 Jul 2026 16:23:16 +0000</pubDate>
      <link>https://dev.to/kaifi_azam_21/this-is-my-fav-design-for-a-web-3dlm</link>
      <guid>https://dev.to/kaifi_azam_21/this-is-my-fav-design-for-a-web-3dlm</guid>
      <description>&lt;div class="crayons-card my-2 p-4"&gt;
  &lt;p class="color-base-60"&gt;Post not found or has been removed.&lt;/p&gt;
&lt;/div&gt;


</description>
    </item>
  </channel>
</rss>
