<?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: Royce</title>
    <description>The latest articles on DEV Community by Royce (@royce_fabbd83cb268312e928).</description>
    <link>https://dev.to/royce_fabbd83cb268312e928</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%2F3797280%2F8e63663e-9eae-47f7-92e0-4522701ef4b7.png</url>
      <title>DEV Community: Royce</title>
      <link>https://dev.to/royce_fabbd83cb268312e928</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/royce_fabbd83cb268312e928"/>
    <language>en</language>
    <item>
      <title>Cytoscape.js vs vis-network vs Sigma.js 2026: Graph Visualization Decision Guide</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 07 Oct 2026 16:00:51 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/cytoscapejs-vs-vis-network-vs-sigmajs-2026-graph-visualization-decision-guide-ibf</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/cytoscapejs-vs-vis-network-vs-sigmajs-2026-graph-visualization-decision-guide-ibf</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/cytoscape-vs-vis-network-vs-sigma-graph-visualization-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Pick &lt;strong&gt;Cytoscape.js&lt;/strong&gt; when the graph is an analysis object: algorithms, layouts, styles, centrality, path finding, and scientific/network workflows matter. Pick &lt;strong&gt;vis-network&lt;/strong&gt; when the product is an interactive network diagram with physics, drag/drop, clustering, and quick editing controls. Pick &lt;strong&gt;Sigma.js&lt;/strong&gt; when the graph is large enough that WebGL rendering and a graphology data layer matter more than built-in algorithms.&lt;/p&gt;

&lt;p&gt;The practical 2026 rule: &lt;strong&gt;Cytoscape for graph analysis, vis-network for interactive diagrams, Sigma for large WebGL graph rendering.&lt;/strong&gt; Benchmark with representative node/edge counts before promising exact limits; layout cost, edge density, labels, and hit-testing usually dominate the user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cytoscape.js is the richest all-in-one graph toolkit.&lt;/strong&gt; Use it when algorithms and layouts are part of the product, not just setup code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vis-network is the fastest path to an interactive network canvas.&lt;/strong&gt; It is strong for physics diagrams, editable nodes, grouping, and exploratory views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sigma.js is a renderer plus graphology, not a batteries-included analysis library.&lt;/strong&gt; That split is a strength for large graphs and typed data flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not cite universal node-count benchmarks.&lt;/strong&gt; Test your own graph shape, labels, edge density, layout strategy, and target hardware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React integration is a lifecycle problem.&lt;/strong&gt; Whichever library owns the canvas/SVG/WebGL subtree should be initialized through a ref and cleaned up explicitly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pick by graph job
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Graph job&lt;/th&gt;
&lt;th&gt;Best first choice&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;th&gt;Watch out for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependency graph with path/centrality queries&lt;/td&gt;
&lt;td&gt;Cytoscape.js&lt;/td&gt;
&lt;td&gt;Built-in algorithms, layouts, and styling are one API&lt;/td&gt;
&lt;td&gt;Large animated layouts can block the main thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-editable network map&lt;/td&gt;
&lt;td&gt;vis-network&lt;/td&gt;
&lt;td&gt;Physics, drag/drop, clustering, DataSet updates, and events are direct&lt;/td&gt;
&lt;td&gt;Physics needs stabilization and may need to be disabled for static views&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large knowledge graph or social graph viewer&lt;/td&gt;
&lt;td&gt;Sigma.js&lt;/td&gt;
&lt;td&gt;WebGL renderer and graphology data layer scale better for dense exploration&lt;/td&gt;
&lt;td&gt;More assembly work for algorithms, labels, and custom interactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React dashboard with small graph widget&lt;/td&gt;
&lt;td&gt;vis-network or Cytoscape.js&lt;/td&gt;
&lt;td&gt;Faster to integrate than a full WebGL/graphology stack&lt;/td&gt;
&lt;td&gt;Destroy/recreate carefully on prop changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scientific or bioinformatics graph analysis&lt;/td&gt;
&lt;td&gt;Cytoscape.js&lt;/td&gt;
&lt;td&gt;Ecosystem and API are built around graph analysis&lt;/td&gt;
&lt;td&gt;Verify extension/layout compatibility for your dataset&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  2026 source snapshot
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Latest npm package checked 2026-06-15&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Package metadata caveat&lt;/th&gt;
&lt;th&gt;GitHub status checked 2026-06-15&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cytoscape.js&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cytoscape@3.34.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;npm unpacked size about 5.7 MB&lt;/td&gt;
&lt;td&gt;Active repo; 11k+ stars; updated 2026-06-14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vis-network&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vis-network@10.1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apache-2.0 OR MIT&lt;/td&gt;
&lt;td&gt;npm unpacked size is large because examples/assets ship with the package&lt;/td&gt;
&lt;td&gt;Active repo; 3.5k+ stars; updated 2026-06-14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sigma.js&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sigma@3.0.3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;npm unpacked size about 1 MB&lt;/td&gt;
&lt;td&gt;Active repo; 12k+ stars; updated 2026-06-14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use package size and stars as context only. They do not prove runtime speed or fit for your graph.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cytoscape.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://js.cytoscape.org" rel="noopener noreferrer"&gt;Cytoscape.js&lt;/a&gt; — graph theory + visualization:&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic graph
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cytoscape&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cytoscape&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cytoscape&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Nodes:&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Remix&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vue&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nuxt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nuxt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;// Edges:&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remix&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nuxt&lt;/span&gt;&lt;span class="dl"&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;span class="na"&gt;style&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="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#3b82f6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data(label)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-valign&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-size&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;12px&lt;/span&gt;&lt;span class="dl"&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;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;line-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#64748b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target-arrow-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#64748b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target-arrow-shape&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;triangle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;curve-style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bezier&lt;/span&gt;&lt;span class="dl"&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;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;  &lt;span class="c1"&gt;// Force-directed layout&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Graph algorithms
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Shortest path:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dijkstra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weight&lt;/span&gt;&lt;span class="dl"&gt;"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pathToVue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pathTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Distance:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;distanceTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;// Centrality:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;centrality&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;betweennessCentrality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;centrality&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;betweenness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Community detection:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clusters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;markovClustering&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;clusters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background-color&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// BFS/DFS:&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Visited:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&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;h3&gt;
  
  
  Layouts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Built-in layouts:&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;          &lt;span class="c1"&gt;// Force-directed&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;         &lt;span class="c1"&gt;// Circular&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// Grid&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;breadthfirst&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// Hierarchical&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;concentric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;     &lt;span class="c1"&gt;// Concentric circles&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;random&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;         &lt;span class="c1"&gt;// Random&lt;/span&gt;

&lt;span class="c1"&gt;// Force-directed with options:&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;idealEdgeLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nodeOverlap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;gravity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;numIter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;animate&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="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  vis-network
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://visjs.github.io/vis-network/" rel="noopener noreferrer"&gt;vis-network&lt;/a&gt; — interactive networks:&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic network
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DataSet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vis-network/standalone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodes&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;DataSet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#61dafb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Remix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#121212&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#42b883&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nuxt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#00dc82&lt;/span&gt;&lt;span class="dl"&gt;"&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;edges&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;DataSet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&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="na"&gt;to&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;powers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&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="na"&gt;to&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;powers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;powers&lt;/span&gt;&lt;span class="dl"&gt;"&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;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;network&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;network&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;Network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;physics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;forceAtlas2Based&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;gravitationalConstant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;centralGravity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;springLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;solver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forceAtlas2Based&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;borderWidth&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="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;width&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="na"&gt;arrows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&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="na"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;middle&lt;/span&gt;&lt;span class="dl"&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;h3&gt;
  
  
  Dynamic updates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add nodes/edges dynamically:&lt;/span&gt;
&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ff3e00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;powers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Remove:&lt;/span&gt;
&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Update:&lt;/span&gt;
&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React 19&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#00d8ff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Physics — stabilize then freeze:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stabilized&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOptions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;physics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;h3&gt;
  
  
  Events
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Click events:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;nodeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Clicked node:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeId&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="c1"&gt;// Hover:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hoverNode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hovering:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Drag:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dragEnd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPositions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New positions:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&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="c1"&gt;// Double-click to edit:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;doubleClick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newLabel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New label:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&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;newLabel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newLabel&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;h3&gt;
  
  
  Clustering
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cluster by property:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;joinCondition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodeOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;nodeOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;frontend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clusterNodeProperties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frontend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;diamond&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#3b82f6&lt;/span&gt;&lt;span class="dl"&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;span class="c1"&gt;// Cluster by connection:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clusterByConnection&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="c1"&gt;// Cluster around node 1&lt;/span&gt;

&lt;span class="c1"&gt;// Open cluster on click:&lt;/span&gt;
&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;selectNode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sigma.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.sigmajs.org" rel="noopener noreferrer"&gt;Sigma.js&lt;/a&gt; — WebGL graph renderer:&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic graph
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sigma&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sigma&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Graph&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graphology&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;graph&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;Graph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Add nodes:&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;x&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="na"&gt;y&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="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#61dafb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;x&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="na"&gt;y&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="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;x&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="na"&gt;y&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="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#42b883&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Add edges:&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;size&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="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#64748b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;size&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="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#64748b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Render:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderer&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;Sigma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;renderEdgeLabels&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Large graph rendering pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sigma&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sigma&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Graph&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graphology&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;forceAtlas2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graphology-layout-forceatlas2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;graph&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;Graph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Generate a representative stress graph for your product.&lt;/span&gt;
&lt;span class="c1"&gt;// Start below your target size, then raise nodeCount/edgeCount on the&lt;/span&gt;
&lt;span class="c1"&gt;// browsers and devices you support; do not reuse these values as a benchmark.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodeCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;edgeCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nodeCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Node &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;x&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;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;y&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;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&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;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`hsl(&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;360&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, 70%, 50%)`&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="c1"&gt;// Add random edges with roughly the same density as the real graph:&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;edgeCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&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;source&lt;/span&gt; &lt;span class="o"&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;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="nx"&gt;nodeCount&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;target&lt;/span&gt; &lt;span class="o"&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;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="nx"&gt;nodeCount&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;source&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;size&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Apply force layout:&lt;/span&gt;
&lt;span class="nx"&gt;forceAtlas2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Render, then profile zoom/pan, labels, search, and hit-testing:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderer&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;Sigma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Search and highlight
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sigma&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sigma&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderer&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;Sigma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Search nodes:&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;matching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filterNodes&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Highlight matching:&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSetting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodeReducer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;matching&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;matching&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#333&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&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="nx"&gt;data&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&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;h3&gt;
  
  
  Events
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderer&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;Sigma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Click:&lt;/span&gt;
&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clickNode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Clicked:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNodeAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Hover:&lt;/span&gt;
&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enterNode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Highlight neighbors:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbors&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;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSetting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodeReducer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;n&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#333&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;leaveNode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSetting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodeReducer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&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;h2&gt;
  
  
  Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Cytoscape.js&lt;/th&gt;
&lt;th&gt;vis-network&lt;/th&gt;
&lt;th&gt;Sigma.js&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Renderer&lt;/td&gt;
&lt;td&gt;Canvas&lt;/td&gt;
&lt;td&gt;Canvas&lt;/td&gt;
&lt;td&gt;WebGL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Practical scale posture&lt;/td&gt;
&lt;td&gt;Small/medium interactive graphs; test complex layouts&lt;/td&gt;
&lt;td&gt;Small/medium interactive networks; tune physics&lt;/td&gt;
&lt;td&gt;Larger interactive graphs through WebGL; still test labels and edge density&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph algorithms&lt;/td&gt;
&lt;td&gt;✅ (many)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Via graphology&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Force layout&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (physics)&lt;/td&gt;
&lt;td&gt;Via graphology&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in drag/drop&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clustering&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Via graphology&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge labels&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node shapes&lt;/td&gt;
&lt;td&gt;✅ (many)&lt;/td&gt;
&lt;td&gt;✅ (many)&lt;/td&gt;
&lt;td&gt;Circle/custom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Animations&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (physics)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React bindings&lt;/td&gt;
&lt;td&gt;Via ref&lt;/td&gt;
&lt;td&gt;Via ref&lt;/td&gt;
&lt;td&gt;@react-sigma&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used by&lt;/td&gt;
&lt;td&gt;Bioinformatics&lt;/td&gt;
&lt;td&gt;Dashboards&lt;/td&gt;
&lt;td&gt;Large networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source snapshot&lt;/td&gt;
&lt;td&gt;npm/GitHub checked 2026-06-15&lt;/td&gt;
&lt;td&gt;npm/GitHub checked 2026-06-15&lt;/td&gt;
&lt;td&gt;npm/GitHub checked 2026-06-15&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  When to Use Each
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use Cytoscape.js if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need graph algorithms (shortest path, centrality, BFS/DFS)&lt;/li&gt;
&lt;li&gt;Building bioinformatics or scientific network analysis&lt;/li&gt;
&lt;li&gt;Need multiple layout algorithms&lt;/li&gt;
&lt;li&gt;Want the richest styling and customization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use vis-network if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building interactive network diagrams&lt;/li&gt;
&lt;li&gt;Need physics-based layout simulation&lt;/li&gt;
&lt;li&gt;Want drag-and-drop node editing&lt;/li&gt;
&lt;li&gt;Need clustering and grouping features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Sigma.js if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rendering large graphs where WebGL, graphology, and explicit profiling matter&lt;/li&gt;
&lt;li&gt;Need WebGL performance for complex networks&lt;/li&gt;
&lt;li&gt;Using graphology for graph algorithms&lt;/li&gt;
&lt;li&gt;Building social network or knowledge graph visualizations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  TypeScript Type Safety and Graph Data Modeling
&lt;/h2&gt;

&lt;p&gt;All three libraries offer TypeScript support, but the quality of type inference differs significantly. Cytoscape.js provides types through &lt;code&gt;@types/cytoscape&lt;/code&gt; and uses a flexible but loosely-typed element data model — &lt;code&gt;ele.data()&lt;/code&gt; returns &lt;code&gt;any&lt;/code&gt;, so you need to cast or validate the shape yourself. The typical pattern is to define your own node and edge data interfaces and cast at read time: &lt;code&gt;const nodeData = node.data() as PackageNodeData&lt;/code&gt;. This works but requires discipline, since the compiler doesn't enforce that data added to the graph matches your interfaces.&lt;/p&gt;

&lt;p&gt;Sigma.js with graphology provides stronger typing through graphology's generic type parameters. &lt;code&gt;new Graph&amp;lt;NodeAttributes, EdgeAttributes, GraphAttributes&amp;gt;()&lt;/code&gt; locks the graph to specific attribute shapes, and &lt;code&gt;graph.getNodeAttributes(node)&lt;/code&gt; returns your typed attributes rather than &lt;code&gt;any&lt;/code&gt;. The &lt;code&gt;graphology-types&lt;/code&gt; package defines the base interfaces, and the broader graphology ecosystem (layout packages, metrics, generators) all respect these generics. This makes Sigma.js with graphology the most type-safe option for teams that need compile-time guarantees about what data lives on their graph elements.&lt;/p&gt;

&lt;p&gt;vis-network sits in the middle — it ships its own TypeScript types and the &lt;code&gt;DataSet&amp;lt;T&amp;gt;&lt;/code&gt; generic enforces the shape of node and edge objects you add. &lt;code&gt;nodes.add({ id: 1, label: "React", group: 3 })&lt;/code&gt; is type-checked against your defined node type. However, vis-network's physics configuration objects are complex and the types can be incomplete for some advanced physics solver options, occasionally requiring &lt;code&gt;@ts-ignore&lt;/code&gt; annotations in heavily customized configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing a Layout Algorithm for Your Graph Structure
&lt;/h2&gt;

&lt;p&gt;All three libraries are DOM-based and require a container element, which creates a seam with React's virtual DOM that each library handles differently. The baseline pattern for all three is using a &lt;code&gt;ref&lt;/code&gt; to get the container element and initializing the library instance inside &lt;code&gt;useEffect&lt;/code&gt; with a cleanup function that destroys the instance on unmount.&lt;/p&gt;

&lt;p&gt;Cytoscape.js with React works well with this pattern because Cytoscape manages its own internal state — you hand it the container element and let it own that DOM subtree. The challenge is data updates: when your graph data changes in React state, you need to call &lt;code&gt;cy.elements().remove()&lt;/code&gt; followed by &lt;code&gt;cy.add(newElements)&lt;/code&gt;, or diff the changes yourself with &lt;code&gt;cy.getElementById()&lt;/code&gt; to find added/removed nodes. The &lt;code&gt;react-cytoscapejs&lt;/code&gt; library wraps this pattern with a &lt;code&gt;&amp;lt;CytoscapeComponent&amp;gt;&lt;/code&gt; that accepts &lt;code&gt;elements&lt;/code&gt; and &lt;code&gt;stylesheet&lt;/code&gt; as React props and handles incremental updates, but it's a thin wrapper that still requires understanding Cytoscape's core API.&lt;/p&gt;

&lt;p&gt;Sigma.js has official React bindings in the &lt;code&gt;@react-sigma&lt;/code&gt; package, which provides &lt;code&gt;&amp;lt;SigmaContainer&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;LoadGraph&amp;gt;&lt;/code&gt;, and &lt;code&gt;useLoadGraph&lt;/code&gt; hooks. The graphology graph object is the data layer — you update it with &lt;code&gt;graph.addNode()&lt;/code&gt;, &lt;code&gt;graph.addEdge()&lt;/code&gt;, &lt;code&gt;graph.mergeNodeAttributes()&lt;/code&gt; and Sigma re-renders automatically because it listens to graphology's event system. This event-driven reactivity is more natural in React than Cytoscape's imperative update API.&lt;/p&gt;

&lt;p&gt;vis-network's DataSet objects are the reactive data layer: &lt;code&gt;nodes.add()&lt;/code&gt;, &lt;code&gt;nodes.update()&lt;/code&gt;, &lt;code&gt;edges.remove()&lt;/code&gt; trigger immediate visual updates without reinitializing the network. This makes React integration straightforward — store the DataSet instances in a ref, update them when props change in a &lt;code&gt;useEffect&lt;/code&gt;, and vis-network reacts automatically.&lt;/p&gt;

&lt;p&gt;Layout algorithm selection has a larger impact on graph readability than any styling choice. Force-directed layouts (Cytoscape's COSE, vis-network's ForceAtlas2Based, graphology's ForceAtlas2) work by simulating spring forces between connected nodes, pushing unconnected nodes apart and pulling connected ones together. They produce natural-looking graph embeddings where clusters of highly-connected nodes group visually, but they are computationally expensive and non-deterministic — the same graph can produce different layouts on different runs. For graphs with clear hierarchical structure (file system trees, organizational charts, dependency trees), breadth-first or Dagre layouts produce cleaner results at lower computational cost.&lt;/p&gt;

&lt;p&gt;The choice of layout algorithm should be driven by graph structure. Biological networks and social graphs benefit from force-directed layouts that reveal community structure. Knowledge graphs and concept maps often do well with force-directed as well. Package dependency graphs — where a few popular packages have many dependents — often look better with hierarchical layouts where the depth corresponds to dependency distance from the root. Cytoscape.js's built-in &lt;code&gt;breadthfirst&lt;/code&gt; and &lt;code&gt;concentric&lt;/code&gt; layouts, or the &lt;code&gt;dagre&lt;/code&gt; extension, are the right choices here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graphology: The Data Layer Behind Sigma.js
&lt;/h2&gt;

&lt;p&gt;Sigma.js doesn't manage its own graph data structure — it renders a graphology &lt;code&gt;Graph&lt;/code&gt; object. Graphology is a separate library (&lt;code&gt;npm install graphology&lt;/code&gt;) with its own extensive ecosystem: &lt;code&gt;graphology-layout-forceatlas2&lt;/code&gt; for force-directed layouts, &lt;code&gt;graphology-communities-louvain&lt;/code&gt; for community detection, &lt;code&gt;graphology-shortest-path&lt;/code&gt; for path finding, &lt;code&gt;graphology-generators&lt;/code&gt; for creating test graphs, and &lt;code&gt;graphology-metrics&lt;/code&gt; for centrality calculations. This separation of concerns is intentional — Sigma is purely a renderer, and graphology is purely a graph data structure with algorithms.&lt;/p&gt;

&lt;p&gt;The graphology ecosystem covers most of what Cytoscape.js builds in: shortest path (Dijkstra, A*), centrality (betweenness, degree, eigenvector), community detection (Louvain, Label Propagation), and force-directed layout (ForceAtlas2, FA2 with Barnes-Hut optimization). The difference is that these are separate npm packages rather than built-in methods. When you're running ForceAtlas2 — graphology's primary layout algorithm — the &lt;code&gt;graphology-layout-forceatlas2&lt;/code&gt; package includes a WebWorker mode (&lt;code&gt;FA2Layout&lt;/code&gt;) that runs the physics simulation on a background thread, keeping the main thread free for rendering. That worker-mode path is useful when layout work threatens interactivity; Cytoscape.js COSE should be treated as main-thread layout work that can make interaction feel blocked during expensive runs, so profile it against representative graphs before promising an interactive limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Boundaries and When to Switch Libraries
&lt;/h2&gt;

&lt;p&gt;Treat graph performance as a workload test, not a universal node-count promise. Cytoscape.js and vis-network both render through Canvas, so layout calculations, event hit-testing, labels, edge density, and redraw frequency compete for main-thread time. Both libraries provide tuning levers — Cytoscape.js has options such as &lt;code&gt;motionBlur&lt;/code&gt;, and vis-network exposes physics solvers including Barnes-Hut-style approximations — but those levers still need to be profiled against your actual graph shape.&lt;/p&gt;

&lt;p&gt;Sigma.js is the better starting point when interactive rendering scale is the main risk because its WebGL renderer batches node and edge drawing through GPU-oriented paths while graphology owns the data layer. That does not make Sigma a guaranteed answer for every large graph: labels, edge density, custom node renderers, search/highlight reducers, layout generation, and the target browser/GPU can still dominate the experience. If you need complex custom shapes, be prepared for WebGL shader work or overlays.&lt;/p&gt;

&lt;p&gt;Use a representative benchmark before switching libraries or promising a limit. Build a fixture with your real node attributes, edge density, label policy, layout algorithm, zoom/search interactions, and target hardware. If Canvas-based interaction becomes visibly unstable after physics/layout tuning, move the rendering spike to Sigma.js; if Sigma still struggles, consider server-side pre-layout, level-of-detail sampling, clustering, or separate overview/detail views before increasing client-side graph size.&lt;/p&gt;




&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;p&gt;This refresh used official docs, npm registry metadata, and GitHub repository metadata checked on 2026-06-15 for Cytoscape.js, vis-network, and Sigma.js. Feature comparison is based on current documented library capabilities, not a synthetic benchmark. Treat dataset-size guidance as directional until you test representative graphs on your target devices.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.pkgpulse.com" rel="noopener noreferrer"&gt;Compare graph visualization and data libraries on PkgPulse →&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See also: &lt;a href="https://www.pkgpulse.com/compare/ava-vs-jest" rel="noopener noreferrer"&gt;AVA vs Jest&lt;/a&gt; and &lt;a href="https://www.pkgpulse.com/guides/mermaid-vs-d3-vs-chartjs-diagrams-data-visualization-2026" rel="noopener noreferrer"&gt;Mermaid vs D3.js vs Chart.js 2026&lt;/a&gt;, &lt;a href="https://www.pkgpulse.com/guides/fabricjs-vs-konva-vs-pixijs-canvas-2d-graphics-2026" rel="noopener noreferrer"&gt;Fabric.js vs Konva vs PixiJS: Canvas &amp;amp; 2D Graphics 2026&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/cytoscape-vs-vis-network-vs-sigma-graph-visualization-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Data Engineering vs Data Science: Courses 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 07 Oct 2026 16:00:36 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/data-engineering-vs-data-science-courses-2026-187m</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/data-engineering-vs-data-science-courses-2026-187m</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/data-engineering-vs-data-science-courses-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Data engineering and data science are adjacent fields that often get confused — sometimes by the companies hiring for them. They require overlapping skills (Python, SQL, statistics) but completely different core expertise, and the job market for each looks different in 2026.&lt;/p&gt;

&lt;p&gt;Understanding the distinction matters before you invest 6-18 months learning one of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Role Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Data Engineering&lt;/th&gt;
&lt;th&gt;Data Science&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core function&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Build and maintain data infrastructure&lt;/td&gt;
&lt;td&gt;Analyze data and build predictive models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary output&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reliable data pipelines and warehouses&lt;/td&gt;
&lt;td&gt;Insights, forecasts, and ML models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Daily tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Spark, Airflow, dbt, Kafka, SQL&lt;/td&gt;
&lt;td&gt;Python, pandas, scikit-learn, Jupyter, SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Programming depth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (software engineering level)&lt;/td&gt;
&lt;td&gt;Moderate (scripting and modeling)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Statistics requirement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low-moderate&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud familiarity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (pipeline infrastructure)&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Median US salary (2026)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$135,000–$165,000&lt;/td&gt;
&lt;td&gt;$110,000–$145,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Job volume (LinkedIn)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~95,000 open roles&lt;/td&gt;
&lt;td&gt;~140,000 open roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Entry difficulty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (SE background helps)&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Data engineers build the systems that make data available, clean, and fast. Data scientists use that data to generate insights and build predictive models. Data engineering pays more and has stronger engineering overlap; data science has more open roles and lower software engineering barriers. If you come from software development, data engineering is the more natural transition. If you come from statistics, finance, or domain expertise, data science is the more natural path.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Data Engineers Actually Do
&lt;/h2&gt;

&lt;p&gt;Data engineers are software engineers who specialize in data infrastructure. The job is less about analyzing data and more about making data analysis possible at scale and reliably.&lt;/p&gt;

&lt;p&gt;A typical data engineering day involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Designing and maintaining ETL/ELT pipelines that move data from source systems (databases, APIs, event streams) into data warehouses&lt;/li&gt;
&lt;li&gt;Configuring and operating pipeline orchestration tools (Apache Airflow, Prefect, Dagster)&lt;/li&gt;
&lt;li&gt;Writing dbt models that transform raw data into clean, queryable tables&lt;/li&gt;
&lt;li&gt;Monitoring pipeline failures and debugging data quality issues&lt;/li&gt;
&lt;li&gt;Provisioning cloud infrastructure for data (Snowflake, BigQuery, Redshift, S3)&lt;/li&gt;
&lt;li&gt;Working with streaming data (Kafka, Kinesis, Flink) for real-time applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What data engineering requires:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strong Python (not just scripting — production-quality, modular, tested code)&lt;/li&gt;
&lt;li&gt;Deep SQL (complex window functions, query optimization, indexing strategy)&lt;/li&gt;
&lt;li&gt;Understanding of distributed systems (why Spark partitions data the way it does, how to avoid data skew)&lt;/li&gt;
&lt;li&gt;Cloud platform knowledge (AWS, GCP, or Azure data services)&lt;/li&gt;
&lt;li&gt;Infrastructure-as-code familiarity (Terraform or cloud-native tools)&lt;/li&gt;
&lt;li&gt;Software engineering practices (version control, CI/CD, testing, monitoring)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "engineer" in data engineering is real. The closest adjacent role is backend software engineering, not data analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Data Scientists Actually Do
&lt;/h2&gt;

&lt;p&gt;Data scientists work with data that the data engineering team has already made available. The job involves understanding business questions, finding patterns in data, building predictive models, and communicating findings to non-technical stakeholders.&lt;/p&gt;

&lt;p&gt;A typical data science day involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exploratory data analysis (EDA) — understanding distributions, relationships, and anomalies&lt;/li&gt;
&lt;li&gt;Feature engineering for machine learning models&lt;/li&gt;
&lt;li&gt;Building, evaluating, and iterating on predictive models (regression, classification, clustering)&lt;/li&gt;
&lt;li&gt;Statistical analysis and A/B test design and evaluation&lt;/li&gt;
&lt;li&gt;Creating visualizations and reports for stakeholders&lt;/li&gt;
&lt;li&gt;Collaborating with product and business teams to define what questions to answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What data science requires:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python (pandas, NumPy, scikit-learn, Matplotlib/Seaborn, and often PyTorch or TensorFlow)&lt;/li&gt;
&lt;li&gt;SQL (joins, aggregations, basic window functions)&lt;/li&gt;
&lt;li&gt;Statistics (probability, hypothesis testing, regression, Bayesian thinking)&lt;/li&gt;
&lt;li&gt;Domain knowledge in the business area you're analyzing&lt;/li&gt;
&lt;li&gt;Communication skills — translating analysis into business decisions&lt;/li&gt;
&lt;li&gt;Machine learning fundamentals (supervised/unsupervised learning, model evaluation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ceiling for data science depth is higher (PhD-level research, novel algorithm development), but the floor is lower than data engineering. You can start doing useful data science work with Python and statistics knowledge. Data engineering requires software engineering foundations that take longer to build.&lt;/p&gt;




&lt;h2&gt;
  
  
  Job Market in 2026
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Data engineering demand has surged.&lt;/strong&gt; The explosion in data volumes, the consolidation around modern data stacks (dbt + cloud warehouses + Airflow), and the realization that most "data science" problems are actually data quality and pipeline problems have driven data engineering demand up significantly. LinkedIn shows ~95,000 open data engineering roles in Q1 2026, up 40% from 2023.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data science hiring has matured and stratified.&lt;/strong&gt; The gold rush of "data scientist" hiring from 2016-2022 has evolved. Companies now distinguish more carefully between analysts (SQL + business reporting), data scientists (ML modeling), and ML engineers (production ML systems). The 140,000 open roles include many analyst positions that don't require ML modeling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI's effect on both roles:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data engineering: AI is expanding the role, not replacing it. LLM-based applications need data pipelines, feature stores, and real-time infrastructure as much as traditional ML.&lt;/li&gt;
&lt;li&gt;Data science: Generative AI has created new tooling but also blurred the line between data scientists and ML engineers. Pure analytics roles (no ML) have commoditized; ML-focused roles have strengthened.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Best Courses for Data Engineering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  IBM Data Engineering Professional Certificate (&lt;a href="https://www.coursefacts.com/platform/coursera" rel="noopener noreferrer"&gt;Coursera&lt;/a&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duration:&lt;/strong&gt; ~3 months at 10 hrs/week | &lt;strong&gt;Cost:&lt;/strong&gt; Free audit / $59/month Coursera Plus&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; Coursera&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A comprehensive structured path covering the full data engineering stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases and SQL for data science&lt;/li&gt;
&lt;li&gt;NoSQL and MongoDB&lt;/li&gt;
&lt;li&gt;Big data with Spark&lt;/li&gt;
&lt;li&gt;Data warehousing (IBM Cognos, but concepts apply broadly)&lt;/li&gt;
&lt;li&gt;ETL pipelines with Python&lt;/li&gt;
&lt;li&gt;Apache Airflow for pipeline orchestration&lt;/li&gt;
&lt;li&gt;Final capstone project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for beginners with some Python/SQL experience who want a structured multi-month path. IBM's certification carries some weight with enterprise hiring teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Engineering with Python (DataCamp Track)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Duration:&lt;/strong&gt; ~50 hours | &lt;strong&gt;Cost:&lt;/strong&gt; $39/month DataCamp subscription&lt;/p&gt;

&lt;p&gt;DataCamp's data engineering track is more practical and more modern than the IBM course. It covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to data engineering&lt;/li&gt;
&lt;li&gt;Building data pipelines with pandas&lt;/li&gt;
&lt;li&gt;Introduction to Airflow&lt;/li&gt;
&lt;li&gt;Building data pipelines with PySpark&lt;/li&gt;
&lt;li&gt;Streaming data with Kafka&lt;/li&gt;
&lt;li&gt;Introduction to dbt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More hands-on than IBM's course but less comprehensive. Best as a complement to the IBM course or for learners who already have programming foundations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full-Stack Data Engineering (Self-Built Path)
&lt;/h3&gt;

&lt;p&gt;For the most in-demand data engineering skills, a curated self-study path outperforms any single course:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SQL:&lt;/strong&gt; Mode Analytics SQL Tutorial (free) + postgresql.org exercises&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python:&lt;/strong&gt; Complete Python Bootcamp (Angela Yu, Udemy, $15) → focus on functions, classes, file I/O&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data pipelines:&lt;/strong&gt; dbt courses (courses.getdbt.com, free) — the best free resource for modern data transformation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; Astronomer's Airflow tutorials (astronomer.io/learn, free)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spark:&lt;/strong&gt; Apache Spark and Python Beginners Guide (Udemy, $15 on sale)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud:&lt;/strong&gt; AWS Data Analytics Specialty or Google Professional Data Engineer prep materials&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project:&lt;/strong&gt; Build an end-to-end pipeline: ingest data from a public API → store in PostgreSQL → transform with dbt → visualize in Metabase or Superset&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Best Courses for Data Science
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Andrew Ng Machine Learning Specialization (Coursera)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duration:&lt;/strong&gt; ~2 months at 9 hrs/week | &lt;strong&gt;Cost:&lt;/strong&gt; Free audit / Coursera Plus&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; Coursera | &lt;strong&gt;Rating:&lt;/strong&gt; 4.9/5 from 170,000+ reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The standard starting point for ML foundations. Covers supervised learning (linear/logistic regression, neural networks), unsupervised learning (clustering, anomaly detection), and reinforcement learning. Uses Python and scikit-learn throughout.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://www.coursefacts.com/guides/andrew-ng-ml-course-review-2026" rel="noopener noreferrer"&gt;Andrew Ng ML course review&lt;/a&gt; for a detailed breakdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Anyone targeting ML-focused data science or AI engineering. The conceptual foundation that makes everything else in data science click.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python for Data Science and Machine Learning Bootcamp — Jose Portilla (Udemy)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Duration:&lt;/strong&gt; ~25 hours | &lt;strong&gt;Cost:&lt;/strong&gt; $11-15 on sale&lt;/p&gt;

&lt;p&gt;Covers the full applied data science Python stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NumPy, pandas, Matplotlib, Seaborn&lt;/li&gt;
&lt;li&gt;Scikit-learn (regression, classification, clustering)&lt;/li&gt;
&lt;li&gt;Natural language processing basics&lt;/li&gt;
&lt;li&gt;Neural networks with Keras&lt;/li&gt;
&lt;li&gt;Capstone projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Less mathematically rigorous than Andrew Ng's course but more tool-focused. Best as a practical companion to the ML Specialization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Statistics and Probability (Khan Academy / StatQuest)
&lt;/h3&gt;

&lt;p&gt;Free, but foundational. StatQuest with Josh Starmer (YouTube, free) is the best resource for making statistics intuitive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Probability distributions&lt;/li&gt;
&lt;li&gt;Hypothesis testing and p-values&lt;/li&gt;
&lt;li&gt;Linear regression derivation&lt;/li&gt;
&lt;li&gt;Bayesian inference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many data science job failures trace to weak statistics, not weak Python. Don't skip this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which Path Fits Your Background
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You come from software engineering (Python, backend, APIs):&lt;/strong&gt;&lt;br&gt;
Data engineering is the natural path. Your software engineering skills transfer directly — you already understand APIs, databases, version control, testing, and production code quality. The learning curve is in distributed systems (Spark) and pipeline tooling (Airflow, dbt), not foundational programming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You come from analytics or business intelligence (Excel, SQL, Tableau):&lt;/strong&gt;&lt;br&gt;
Data science is the more accessible path. You already understand the business context, data interpretation, and stakeholder communication. The learning curve is in statistics, Python, and machine learning — all learnable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You come from math or statistics (academic or actuarial background):&lt;/strong&gt;&lt;br&gt;
Data science is the natural fit. Your statistics background is the hardest thing to learn; Python and ML tooling are more learnable than the statistical intuition you already have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You're starting fresh with no relevant background:&lt;/strong&gt;&lt;br&gt;
Data engineering has a higher initial learning curve (requires software engineering foundations) but often has faster salary progression. Data science is more accessible as an entry point but the ML engineering jobs worth the most are still technically demanding.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Overlap: Skills Both Roles Need
&lt;/h2&gt;

&lt;p&gt;Both data engineers and data scientists need strong SQL and Python. Developing both before specializing is efficient:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQL:&lt;/strong&gt; Write complex queries, understand indexes and query planning, know window functions (ROW_NUMBER, LAG, LEAD, running totals). Mode Analytics Tutorial (free) + LeetCode SQL problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python:&lt;/strong&gt; Functions, classes, file I/O, working with APIs, pandas for data manipulation. The Python skills needed overlap between both roles — master pandas and you're useful in either direction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud basics:&lt;/strong&gt; Know enough AWS, GCP, or Azure to understand where data lives and how it moves. Both roles need this, though data engineers go much deeper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version control:&lt;/strong&gt; Git is table stakes for both roles at professional level.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Data engineering pays more&lt;/strong&gt; ($135K-$165K median vs. $110K-$145K) and has lower saturation relative to data science — but requires software engineering foundations that take longer to build if you're starting from non-technical backgrounds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data science has more open roles&lt;/strong&gt; and a more accessible entry point, but the highest-value positions (ML engineer, applied scientist at tech companies) are competitive and require strong statistics and software skills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The practical recommendation:&lt;/strong&gt; If you have 6-12 months and a software engineering background, go data engineering. If you have 12-18 months and a quantitative but non-engineering background, go data science with an ML engineering focus.&lt;/p&gt;

&lt;p&gt;Either path: build a public portfolio of completed projects. Both fields hire based on demonstrated skills, not degrees or course completions.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://www.coursefacts.com/guides/best-data-engineering-courses-2026" rel="noopener noreferrer"&gt;best data engineering courses guide&lt;/a&gt; for the full breakdown of data engineering course options, and the &lt;a href="https://www.coursefacts.com/guides/andrew-ng-ml-course-review-2026" rel="noopener noreferrer"&gt;Andrew Ng ML Specialization review&lt;/a&gt; for the most recommended data science starting point.&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.coursefacts.com/guides/data-engineering-vs-data-science-courses-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mux vs Cloudflare Stream vs Bunny Stream 2026: Video CDN and Streaming Platform Guide</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 30 Sep 2026 16:00:29 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/mux-vs-cloudflare-stream-vs-bunny-stream-2026-video-cdn-and-streaming-platform-guide-1m0b</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/mux-vs-cloudflare-stream-vs-bunny-stream-2026-video-cdn-and-streaming-platform-guide-1m0b</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/mux-vs-cloudflare-stream-vs-bunny-stream-video-cdn-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Hosting video yourself means encoding pipelines, CDN distribution, adaptive bitrate streaming, and player maintenance. Video hosting APIs abstract this into a simple upload-and-stream workflow. &lt;strong&gt;Mux&lt;/strong&gt; is the developer-first video infrastructure platform — upload a video, get HLS adaptive bitrate streams, thumbnails, GIF previews, captions, and per-second analytics; designed for SaaS products embedding video. &lt;strong&gt;Cloudflare Stream&lt;/strong&gt; is the Cloudflare-native option — deeply integrated into the Cloudflare network, streams through the same CDN as your other Cloudflare assets, and keeps the API surface small. &lt;strong&gt;Bunny Stream&lt;/strong&gt; is the cost-control candidate for high-volume libraries — European-based CDN infrastructure, configurable video processing, and a built-in player with DRM options. For developer-first video products with analytics: Mux. For Cloudflare users wanting the simplest integration: Cloudflare Stream. For cost-sensitive applications with high video volume: model Bunny Stream against current pricing and feature needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choose Mux when video workflow and viewer-quality analytics are product features.&lt;/strong&gt; It has the strongest developer workflow, player components, webhooks, and Mux Data story.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose Cloudflare Stream when Cloudflare-native simplicity is the main requirement.&lt;/strong&gt; It is a good fit for teams already using Cloudflare for CDN, Pages, Workers, DNS, and access controls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose Bunny Stream when bandwidth/storage cost and CDN control dominate the decision.&lt;/strong&gt; It is attractive for high-volume VOD and cost-sensitive libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use current pricing pages before committing.&lt;/strong&gt; Video pricing changes quickly and mixes storage minutes, viewed minutes, encoding minutes, bandwidth, DRM, live, and analytics add-ons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All three can support direct upload and HLS playback.&lt;/strong&gt; The real differences show up in webhooks, private playback, analytics depth, player UX, live workflows, and migration/export needs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Above-fold recommendation table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product situation&lt;/th&gt;
&lt;th&gt;Pick first&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;th&gt;Check before launch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SaaS product where playback quality affects retention&lt;/td&gt;
&lt;td&gt;Mux&lt;/td&gt;
&lt;td&gt;Developer workflow, player components, webhooks, Mux Data, signed playback patterns&lt;/td&gt;
&lt;td&gt;Whether Mux Data/advanced encoding cost is justified at your volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App already on Cloudflare stack&lt;/td&gt;
&lt;td&gt;Cloudflare Stream&lt;/td&gt;
&lt;td&gt;Fewer vendors and simpler Cloudflare-native operations&lt;/td&gt;
&lt;td&gt;Private playback, analytics depth, and custom player requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-volume VOD library with cost pressure&lt;/td&gt;
&lt;td&gt;Bunny Stream&lt;/td&gt;
&lt;td&gt;Cost-sensitive CDN/storage posture and configurable video library features&lt;/td&gt;
&lt;td&gt;DRM/private playback, analytics needs, and migration/export story&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need custom encode pipeline or unusual codecs&lt;/td&gt;
&lt;td&gt;Self-host/encode separately&lt;/td&gt;
&lt;td&gt;FFmpeg pipeline gives maximum control&lt;/td&gt;
&lt;td&gt;Operations burden, storage, queues, CDN, captions, thumbnails, and monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Pricing caveat checked 2026-06-15
&lt;/h2&gt;

&lt;p&gt;Pricing should be verified from the provider pages during implementation because the units differ: Mux exposes video/storage/delivery/analytics dimensions, Cloudflare Stream is Cloudflare-platform oriented, and Bunny combines Stream library settings with CDN/storage economics. Avoid hardcoding a long-lived winner from a single price row; model your own minutes stored, minutes viewed, GB delivered, live hours, DRM/private playback, and analytics needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SaaS with video + analytics (like Loom, Wistia)  → Mux (Mux Data analytics)
Already on Cloudflare (CDN, Workers, Pages)       → Cloudflare Stream
High-volume VOD on a budget                       → Bunny Stream
DRM content protection                            → Bunny Stream or Mux
Low-latency live streaming                        → Compare each provider's current live-streaming latency, protocol, and packaging options
Simple video embeds with no analytics             → Cloudflare Stream
European data residency                           → Bunny Stream (EU-based)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Mux: Developer-First Video Infrastructure
&lt;/h2&gt;

&lt;p&gt;Mux is the video platform designed for SaaS developers — upload via URL or direct, get playback URLs, thumbnails, GIF previews, captions, and detailed viewer analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @mux/mux-node         &lt;span class="c"&gt;# Server SDK&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @mux/mux-player-react  &lt;span class="c"&gt;# Video player component&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upload Video from URL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Mux&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mux/mux-node&lt;/span&gt;&lt;span class="dl"&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;mux&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;Mux&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MUX_TOKEN_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tokenSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MUX_TOKEN_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Create an asset from a URL (Mux downloads and processes it)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadVideoFromUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;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;asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;videoUrl&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="na"&gt;playback_policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;mp4_support&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;capped-1080p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// Also generate MP4 for download&lt;/span&gt;
    &lt;span class="na"&gt;encoding_tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;baseline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// "baseline" | "smart"&lt;/span&gt;
    &lt;span class="na"&gt;video_quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;master_access&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asset ID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Playback ID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playback_ids&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Poll for asset status (or use webhooks)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;waitForAssetReady&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Asset&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetId&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="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preparing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetId&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="nx"&gt;asset&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;h3&gt;
  
  
  Direct Browser Upload
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server: Create an upload URL&lt;/span&gt;
&lt;span class="c1"&gt;// app/api/mux/upload/route.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&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;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;new_asset_settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;playback_policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;encoding_tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;baseline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;cors_origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_APP_URL&lt;/span&gt;&lt;span class="o"&gt;!&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="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;uploadId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;uploadUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// PUT video bytes directly to this URL&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Client: Upload file directly to Mux&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;UpChunk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mux/upchunk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;uploadUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/mux/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UpChunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUpload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uploadUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30720&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 30MB chunks&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setUploadProgress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Upload complete!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Upload error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&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;h3&gt;
  
  
  Mux Player (React)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MuxPlayer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mux/mux-player-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;VideoPlayer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;playbackId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MuxPlayer&lt;/span&gt;
      &lt;span class="na"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;playbackId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;video_title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My Video&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;viewer_user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// For Mux Data viewer analytics&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;streamType&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"on-demand"&lt;/span&gt;
      &lt;span class="na"&gt;autoPlay&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;poster&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://image.mux.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/thumbnail.jpg?time=10`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16/9&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Thumbnail URL patterns&lt;/span&gt;
&lt;span class="c1"&gt;// https://image.mux.com/{PLAYBACK_ID}/thumbnail.jpg?time=10    (still at 10s)&lt;/span&gt;
&lt;span class="c1"&gt;// https://image.mux.com/{PLAYBACK_ID}/animated.gif?start=10&amp;amp;end=15  (animated GIF)&lt;/span&gt;
&lt;span class="c1"&gt;// https://image.mux.com/{PLAYBACK_ID}/storyboard.vtt  (seeking preview sprites)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Webhooks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/mux/webhook/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/headers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Mux&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mux/mux-node&lt;/span&gt;&lt;span class="dl"&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;mux&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;Mux&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MUX_TOKEN_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;tokenSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MUX_TOKEN_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;headersList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;headers&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;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headersList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mux-Signature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Verify webhook signature&lt;/span&gt;
  &lt;span class="nx"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webhooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verifySignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mux-signature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MUX_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="o"&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;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video.asset.ready&lt;/span&gt;&lt;span class="dl"&gt;"&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;asset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;muxAssetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playback_ids&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&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="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video.asset.errored&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;muxAssetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;break&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;received&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Signed Playback (Private Videos)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create signed playback token for private assets&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSignedPlaybackToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;now&lt;/span&gt; &lt;span class="o"&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;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;aud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// "v" = video, "t" = thumbnail, "g" = gif, "s" = storyboard&lt;/span&gt;
      &lt;span class="na"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// 1 hour expiry&lt;/span&gt;
      &lt;span class="na"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;keyId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RS256&lt;/span&gt;&lt;span class="dl"&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;span class="c1"&gt;// Use in player&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignedPlaybackToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;playbackId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keyId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// https://stream.mux.com/{PLAYBACK_ID}.m3u8?token={TOKEN}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cloudflare Stream: Simplest Video API
&lt;/h2&gt;

&lt;p&gt;Cloudflare Stream is the lowest-friction video API — especially for teams already on Cloudflare. Upload a video, embed it, done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct Upload from Browser
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server: Get a one-time upload URL&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createStreamUploadUrl&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;uploadUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.cloudflare.com/client/v4/accounts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CF_ACCOUNT_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/stream/direct_upload`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CF_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;maxDurationSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;requireSignedURLs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User Upload&lt;/span&gt;&lt;span class="dl"&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;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="na"&gt;uploadUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploadURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Client: Upload directly to Cloudflare&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadToCloudflare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;uploadUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/stream/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="c1"&gt;// Direct TUS upload&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;tus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uploadUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 50MB chunks&lt;/span&gt;
    &lt;span class="na"&gt;onProgress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uploaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setProgress&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;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;uploaded&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Upload complete! Video UID:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// Poll: https://api.cloudflare.com/.../{uid} until readyToStream: true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&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;h3&gt;
  
  
  Embed Player
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cloudflare Stream iframe embed&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CloudflarePlayer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;videoId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;paddingTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;56.25%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://customer-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_CF_CUSTOMER_CODE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.cloudflarestream.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/iframe`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;"&lt;/span&gt;
        &lt;span class="na"&gt;allowFullScreen&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;top&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="na"&gt;left&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="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;h3&gt;
  
  
  List and Manage Videos
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;listVideos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.cloudflare.com/client/v4/accounts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/stream`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Array of video objects&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.cloudflare.com/client/v4/accounts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CF_ACCOUNT_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/stream/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CF_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Bunny Stream: Cost-Efficient Video CDN
&lt;/h2&gt;

&lt;p&gt;Bunny Stream offers competitive pricing with global CDN, video processing, and optional DRM — popular for high-volume content delivery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload and Manage via REST API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BUNNY_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BUNNY_API_KEY&lt;/span&gt;&lt;span class="o"&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;BUNNY_LIBRARY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BUNNY_LIBRARY_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create a video entry&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createBunnyVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://video.bunnycdn.com/library/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BUNNY_LIBRARY_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/videos`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;AccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUNNY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="na"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;guid&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Upload video bytes&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadBunnyVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;videoBuffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://video.bunnycdn.com/library/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BUNNY_LIBRARY_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/videos/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;AccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUNNY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/octet-stream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;videoBuffer&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;span class="c1"&gt;// Full upload pipeline&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;videoPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;videoId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createBunnyVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&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;videoBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;uploadBunnyVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;videoBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Playback URL: https://[hostname].b-cdn.net/{videoId}/playlist.m3u8&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;videoId&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;h3&gt;
  
  
  Embed Player
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bunny Stream embeds via iframe&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BunnyPlayer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;libraryId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;libraryId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;paddingTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;56.25%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://iframe.mediadelivery.net/embed/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;libraryId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;videoId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?autoplay=false&amp;amp;loop=false&amp;amp;muted=false&amp;amp;preload=true`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
        &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;"&lt;/span&gt;
        &lt;span class="na"&gt;allowFullScreen&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;top&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="na"&gt;left&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="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;h2&gt;
  
  
  Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Mux&lt;/th&gt;
&lt;th&gt;Cloudflare Stream&lt;/th&gt;
&lt;th&gt;Bunny Stream&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Adaptive bitrate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ HLS&lt;/td&gt;
&lt;td&gt;✅ HLS&lt;/td&gt;
&lt;td&gt;✅ HLS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Direct browser upload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (TUS)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom player&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Mux Player&lt;/td&gt;
&lt;td&gt;✅ Iframe/SDK&lt;/td&gt;
&lt;td&gt;✅ Iframe/SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Analytics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Mux Data&lt;/td&gt;
&lt;td&gt;✅ Basic&lt;/td&gt;
&lt;td&gt;✅ Basic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DRM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ Widevine/FairPlay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live streaming&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ RTMP&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Signed URLs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Captions/subtitles&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Auto-generate&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Webhook events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-dimensional video platform pricing; verify storage/delivery/analytics/live units&lt;/td&gt;
&lt;td&gt;Cloudflare Stream platform pricing; verify viewed/stored minute model and account limits&lt;/td&gt;
&lt;td&gt;Stream/CDN-oriented pricing; verify storage, delivery, encoding, DRM, and region assumptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best pricing due diligence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Model analytics and advanced encoding separately&lt;/td&gt;
&lt;td&gt;Model Cloudflare account/platform coupling&lt;/td&gt;
&lt;td&gt;Model delivery volume and library settings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  When to self-host or roll your own encoding
&lt;/h2&gt;

&lt;p&gt;Skip these hosted platforms only when control is worth the operations burden: custom codecs, unusual processing, strict data residency, advanced DRM packaging, very high predictable volume, or a product that already owns FFmpeg workers, storage, queues, CDN configuration, captions, thumbnails, and monitoring. For most SaaS products, a hosted video platform is cheaper than rebuilding the whole pipeline badly.&lt;/p&gt;

&lt;p&gt;If you need that control, start with &lt;a href="https://www.pkgpulse.com/guides/fluent-ffmpeg-vs-ffmpeg-wasm-vs-node-video-lib-video-2026" rel="noopener noreferrer"&gt;Fluent FFmpeg vs ffmpeg-wasm vs node-video-lib&lt;/a&gt; and treat the hosted providers as upload/playback/CDN alternatives, not as the only way to process video.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Each
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choose Mux if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a SaaS product with video as a core feature (education platform, content creation, video hosting)&lt;/li&gt;
&lt;li&gt;Per-viewer analytics (quality score, rebuffering rate, startup time) are important&lt;/li&gt;
&lt;li&gt;Developer experience is a priority — best SDK, best documentation, best DX&lt;/li&gt;
&lt;li&gt;Automatic captions and thumbnail generation are needed&lt;/li&gt;
&lt;li&gt;GIF preview generation for hover-to-preview UX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose Cloudflare Stream if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're already a Cloudflare customer (domain, CDN, Workers)&lt;/li&gt;
&lt;li&gt;Simplest possible integration — minimal API surface&lt;/li&gt;
&lt;li&gt;You have verified the current free allowance or trial terms are sufficient for testing or low-volume use&lt;/li&gt;
&lt;li&gt;Cost is the priority and your model favors Cloudflare's current storage/viewing-minute units&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose Bunny Stream if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High-volume video delivery where per-GB CDN cost matters most&lt;/li&gt;
&lt;li&gt;European data residency required (Bunny.net is EU-based)&lt;/li&gt;
&lt;li&gt;DRM is needed without enterprise pricing&lt;/li&gt;
&lt;li&gt;Budget-conscious — current Bunny pricing, CDN geography, and library settings look favorable in your own volume model&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Encoding Pipeline and Processing Time
&lt;/h2&gt;

&lt;p&gt;When a video is uploaded to any of these platforms, it goes through an encoding pipeline before it's available for playback. The time this takes and the output quality varies in ways that matter at scale.&lt;/p&gt;

&lt;p&gt;Mux exposes Baseline and Smart encoding options, and Smart encoding is the per-title path to evaluate when storage footprint, rendition ladders, or delivered bitrate matter. Do not assume a universal processing-time or byte-savings number: results depend on source duration, resolution, motion complexity, configured quality tier, and current provider behavior. Use Mux's current docs for supported settings, listen for the &lt;code&gt;video.asset.ready&lt;/code&gt; webhook, and run a representative upload test with your own source videos before promising launch-time readiness or CDN-savings estimates.&lt;/p&gt;

&lt;p&gt;Cloudflare Stream also processes uploads before playback and exposes the &lt;code&gt;readyToStream: true&lt;/code&gt; field on the video object when playback is available. Treat processing time and output efficiency as implementation due diligence rather than fixed guide-level numbers: compare Cloudflare's current docs, upload the same representative source videos you test elsewhere, inspect the generated playback behavior, and model storage/viewing-minute or bandwidth impact from measured outputs. For most simple embed use cases, the operational simplicity may matter more than fine-grained encode tuning; for cost-sensitive libraries, verify that tradeoff with current provider behavior instead of assuming one platform always delivers fewer bytes.&lt;/p&gt;

&lt;p&gt;Bunny Stream's encoding pipeline is the most configurable: you specify which resolutions to generate, enable or disable specific renditions, and set quality presets per video library. This matters for high-volume content pipelines where generating unnecessary renditions wastes storage. Bunny also supports vertical video encoding (9:16 aspect ratio) as an explicit option, which matters for social media content pipelines where portrait format is standard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Analytics and Viewer Intelligence
&lt;/h2&gt;

&lt;p&gt;The gap in analytics between these platforms is significant enough to be a primary decision factor for products where video quality is a user experience concern.&lt;/p&gt;

&lt;p&gt;Mux Data is a separate but deeply integrated product that captures per-second video quality events from every viewer session. Every rebuffering event, quality switch, startup delay, and error is captured and queryable. The Mux Data dashboard shows startup time broken down by geography, rebuffering rate by device type, and error rate by video. For a SaaS company where video quality directly affects user retention, this is the data you need to diagnose and fix playback problems before users complain. Mux Data also works with non-Mux video sources — you can instrument a Cloudflare Stream or Bunny Stream HLS URL with Mux Data's player SDK and get the same quality analytics.&lt;/p&gt;

&lt;p&gt;Cloudflare Stream provides basic analytics: total views, bandwidth consumption, and aggregate error rates. The data is available in the Cloudflare Dashboard and the analytics API. There's no per-viewer session tracking, no quality event capture, and no geographic breakdown of buffering performance — just aggregated counts. This is sufficient for simple embed use cases but not for products where playback quality is a tracked product metric.&lt;/p&gt;

&lt;p&gt;Bunny Stream offers play counts, bandwidth analytics, and country-level geographic distribution through its dashboard. Like Cloudflare, this is aggregate data without per-session quality tracking. Teams that need quality analytics on top of Bunny Stream typically instrument the player separately — either with Mux Data, Datadog RUM, or a custom analytics layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Player Customization and Embedding
&lt;/h2&gt;

&lt;p&gt;Each platform provides an iframe embed, but the degree of player customization available without building a custom implementation varies substantially.&lt;/p&gt;

&lt;p&gt;Mux ships &lt;code&gt;@mux/mux-player-react&lt;/code&gt; and a &lt;code&gt;mux-player&lt;/code&gt; web component — both wrap the underlying HLS.js engine with Mux's own UI shell. The player supports custom thumbnails, chapter markers, caption tracks with styling, and includes Mux Data instrumentation by default. For teams with strong design requirements, CSS custom properties expose most visual parameters — colors, control bar layout, icon styles — without requiring a fork. The player source is open and forkable for deeper customization.&lt;/p&gt;

&lt;p&gt;Cloudflare Stream's embed is a plain iframe. There is no React component or web component — you write the iframe HTML directly. For custom player experiences with Cloudflare Stream as the backend, you use HLS.js or video.js directly and point it at the Cloudflare Stream HLS manifest URL. This is technically straightforward but requires building all player controls, keyboard shortcuts, and accessibility from scratch or from a player library.&lt;/p&gt;

&lt;p&gt;Bunny Stream similarly provides an iframe embed with a configurable player skin, but no React SDK. Custom player implementations use standard HLS.js against Bunny's manifest URLs. For teams that need pixel-precise control over the video player UI, Cloudflare Stream and Bunny Stream both require more custom development than Mux's player component.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure modes to plan for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Egress and viewed-minute surprises:&lt;/strong&gt; run cost models on realistic average watch time, not just upload count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook retries and idempotency:&lt;/strong&gt; asset-ready and error events must be safe to receive more than once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private playback and DRM:&lt;/strong&gt; signed URL, token, and DRM workflows differ by provider and can change player choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live streaming latency:&lt;/strong&gt; live/VOD pricing and latency targets are separate decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migration/export:&lt;/strong&gt; document how to export source files, thumbnails, captions, and playback metadata before the library grows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional compliance:&lt;/strong&gt; check where media is stored, processed, and delivered if customer contracts care.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;p&gt;Data sourced from official Mux documentation and pricing, Cloudflare Stream documentation and product pages, Bunny Stream documentation and pricing, plus npm registry metadata for &lt;code&gt;@mux/mux-node@14.1.1&lt;/code&gt; and &lt;code&gt;@mux/mux-player-react@3.13.0&lt;/code&gt;, all checked on 2026-06-15. Pricing details are intentionally framed as due-diligence prompts instead of permanent price claims.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Related: &lt;a href="https://www.pkgpulse.com/guides/fluent-ffmpeg-vs-ffmpeg-wasm-vs-node-video-lib-video-2026" rel="noopener noreferrer"&gt;Fluent FFmpeg vs ffmpeg-wasm vs node-video-lib&lt;/a&gt; for self-hosted video processing before uploading, or &lt;a href="https://www.pkgpulse.com/guides/remotion-vs-motion-canvas-vs-revideo-programmatic-video-2026" rel="noopener noreferrer"&gt;Remotion vs Motion Canvas vs Revideo&lt;/a&gt; for programmatically generating video content to host on these platforms.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See also: &lt;a href="https://www.pkgpulse.com/compare/bun-vs-vite" rel="noopener noreferrer"&gt;Bun vs Vite&lt;/a&gt; and &lt;a href="https://www.pkgpulse.com/guides/livekit-vs-agora-vs-100ms-real-time-video-audio-sdks-2026" rel="noopener noreferrer"&gt;LiveKit vs Agora vs 100ms 2026&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/mux-vs-cloudflare-stream-vs-bunny-stream-video-cdn-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>GitHub Copilot vs Cursor 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 30 Sep 2026 16:00:20 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/github-copilot-vs-cursor-2026-5a6p</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/github-copilot-vs-cursor-2026-5a6p</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/github-copilot-vs-cursor-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Choose &lt;strong&gt;GitHub Copilot&lt;/strong&gt; if your team already lives in GitHub, wants lower rollout friction, and needs AI assistance inside existing editors, pull requests, and organization policy controls. Choose &lt;strong&gt;Cursor&lt;/strong&gt; if you want an AI-first coding environment for repo-wide edits, agent mode, rules, MCP integrations, skills, and CLI-assisted workflows.&lt;/p&gt;

&lt;p&gt;The 2026 comparison is no longer "autocomplete vs chat." Both tools can help write, explain, test, and review code. The real difference is workflow ownership: Copilot extends the GitHub developer workflow; Cursor tries to make the editor itself the AI coding workspace.&lt;/p&gt;

&lt;p&gt;If you have already chosen Copilot and need training options, use our &lt;a href="https://www.coursefacts.com/guides/best-github-copilot-courses-2026" rel="noopener noreferrer"&gt;best GitHub Copilot courses guide&lt;/a&gt;. If you are leaning toward Cursor, use our &lt;a href="https://www.coursefacts.com/guides/best-cursor-courses-2026" rel="noopener noreferrer"&gt;best Cursor courses guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source check: GitHub Copilot docs/product pages and Cursor public docs/product pages were checked on May 22, 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick verdict
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Better default&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise GitHub organization&lt;/td&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;Easier procurement, policy, seat, and repository workflow alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solo builder moving fast&lt;/td&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;Higher ceiling for multi-file edits and AI-first iteration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team standardized on VS Code/JetBrains&lt;/td&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;Less workflow disruption and easier onboarding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer wants agentic IDE workflow&lt;/td&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;Agent mode, rules, repo context, MCP, skills, and CLI are central to the product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security/procurement buyer&lt;/td&gt;
&lt;td&gt;GitHub Copilot first&lt;/td&gt;
&lt;td&gt;It is simpler to explain as an extension of GitHub governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refactor-heavy product engineer&lt;/td&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;Better fit when the task spans many files, tests, and follow-up edits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What changed in 2026
&lt;/h2&gt;

&lt;p&gt;The old comparison made Copilot sound like a lightweight autocomplete plugin and Cursor sound like chat bolted onto VS Code. That framing is stale.&lt;/p&gt;

&lt;p&gt;GitHub now positions Copilot as a broader AI pair programmer across editor, GitHub, review, chat, and agent-style work. Cursor's public docs emphasize an AI-first coding environment with Agent, Rules, MCP, Skills, CLI, models, and team setup. The overlap is larger, but the product philosophies are still different.&lt;/p&gt;

&lt;p&gt;Copilot is best understood as &lt;strong&gt;AI inside the existing GitHub workflow&lt;/strong&gt;. Cursor is best understood as &lt;strong&gt;the coding workspace rebuilt around AI interactions&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core product difference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Copilot: AI inside familiar developer tools
&lt;/h3&gt;

&lt;p&gt;Copilot's advantage is organizational fit. It works inside the tools many teams already trust, including GitHub and major IDEs. That matters when the buyer is not only an individual developer but also security, platform engineering, finance, legal, and engineering leadership.&lt;/p&gt;

&lt;p&gt;Copilot is strongest when you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;autocomplete and chat inside an approved IDE;&lt;/li&gt;
&lt;li&gt;pull-request help and GitHub-native review workflow;&lt;/li&gt;
&lt;li&gt;organization-level policy and seat management;&lt;/li&gt;
&lt;li&gt;a common assistant that many developers can adopt without changing editors;&lt;/li&gt;
&lt;li&gt;a training plan that fits GitHub and Microsoft Learn resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cursor: an AI-first coding environment
&lt;/h3&gt;

&lt;p&gt;Cursor's advantage is workflow depth for the individual developer or focused product team. It is not just a place to call a model; it is built around repo context, agent-driven changes, reusable rules, MCP servers, skills, CLI entry points, and a coding loop where the assistant can help plan and execute multi-file tasks.&lt;/p&gt;

&lt;p&gt;Cursor is strongest when you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a dedicated AI coding environment rather than an IDE plugin;&lt;/li&gt;
&lt;li&gt;multi-file edits with fewer manual context hops;&lt;/li&gt;
&lt;li&gt;rules and repo conventions the assistant should follow;&lt;/li&gt;
&lt;li&gt;MCP/tooling integrations inside the editor workflow;&lt;/li&gt;
&lt;li&gt;faster iteration on tickets, tests, and refactors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where GitHub Copilot wins
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Enterprise rollout
&lt;/h3&gt;

&lt;p&gt;Copilot is often the first AI coding assistant an organization can approve. The reason is not that every developer will prefer it. The reason is that GitHub already sits close to source control, pull requests, permissions, billing, and policy conversations.&lt;/p&gt;

&lt;p&gt;If the company already uses GitHub Enterprise, Copilot has a clearer adoption story than asking every developer to move to a new editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Familiar editor workflow
&lt;/h3&gt;

&lt;p&gt;Many developers do not want their editor to become an AI lab. They want suggestions, chat, test generation, and explanations while they keep their existing workflow. Copilot fits that preference.&lt;/p&gt;

&lt;p&gt;This matters for teams with mixed seniority. A senior engineer may want a full agentic environment, while a junior engineer may need a smaller assistant that does not hide too much of the implementation process.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. GitHub-native review and repository context
&lt;/h3&gt;

&lt;p&gt;Copilot's GitHub-native position is valuable when the work moves from local code to issues, pull requests, review comments, and repository maintenance. Teams that measure work through GitHub can train Copilot usage inside the same operational surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Cursor wins
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Multi-file implementation work
&lt;/h3&gt;

&lt;p&gt;Cursor usually feels stronger when the task sounds like a ticket rather than a snippet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"add this form flow and tests";&lt;/li&gt;
&lt;li&gt;"refactor these shared types";&lt;/li&gt;
&lt;li&gt;"trace this bug across frontend and API code";&lt;/li&gt;
&lt;li&gt;"update the component, route, and test in one pass".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kind of work benefits from repo-level reasoning and an editor that expects the assistant to manage context across files.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Rules, MCP, skills, and agent workflows
&lt;/h3&gt;

&lt;p&gt;Cursor's public docs now make Agent, Rules, MCP, Skills, CLI, and team setup central. That matters for developers who want to turn repeated guidance into reusable project behavior: coding standards, repo rules, tool servers, runbooks, and command-line entry points.&lt;/p&gt;

&lt;p&gt;Copilot can help with pieces of those workflows. Cursor more naturally becomes the environment where those workflows live.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Individual leverage
&lt;/h3&gt;

&lt;p&gt;For a solo developer, startup engineer, or product-minded builder, Cursor can create a larger sense of leverage because the assistant is allowed to participate in bigger units of work. The tradeoff is that you must get better at steering, reviewing, and testing. More power also means more responsibility for bad diffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training implications
&lt;/h2&gt;

&lt;p&gt;If you choose Copilot, the best training path is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/copilot" rel="noopener noreferrer"&gt;GitHub Copilot official docs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Microsoft Learn or GitHub training modules for team rollout.&lt;/li&gt;
&lt;li&gt;One internal repo exercise focused on tests, review, and safe acceptance.&lt;/li&gt;
&lt;li&gt;Optional video catalog training from LinkedIn Learning or Pluralsight.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See the &lt;a href="https://www.coursefacts.com/guides/best-github-copilot-courses-2026" rel="noopener noreferrer"&gt;best GitHub Copilot courses guide&lt;/a&gt; for the full roundup.&lt;/p&gt;

&lt;p&gt;If you choose Cursor, the best training path is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cursor docs for Agent, Rules, MCP, Skills, CLI, and team setup.&lt;/li&gt;
&lt;li&gt;A repo-specific rules file or checklist that tells the assistant how to work.&lt;/li&gt;
&lt;li&gt;A small implementation task with tests and a strict diff review.&lt;/li&gt;
&lt;li&gt;Follow-up practice on refactors, debugging, and context-heavy tasks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See the &lt;a href="https://www.coursefacts.com/guides/best-cursor-courses-2026" rel="noopener noreferrer"&gt;best Cursor courses guide&lt;/a&gt; for Cursor-specific options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing and value
&lt;/h2&gt;

&lt;p&gt;Do not decide only by sticker price. For an individual, a tool that saves a few hours per month can pay for itself quickly. For a team, the bigger cost is training, policy, review quality, data governance, and inconsistent adoption.&lt;/p&gt;

&lt;p&gt;Copilot tends to have a smoother organization-wide ROI story because it fits existing GitHub workflows. Cursor tends to have a higher upside for developers who are willing to work inside an AI-native environment and learn its conventions deeply.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which should software engineers learn first?
&lt;/h2&gt;

&lt;p&gt;If you are a software engineer building AI-adjacent products, learn the workflow that matches your next three months.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your employer has Copilot seats, learn Copilot first and use it inside the approved workflow.&lt;/li&gt;
&lt;li&gt;If you are building a side project or startup and can choose your environment, try Cursor on a real ticket.&lt;/li&gt;
&lt;li&gt;If you want to understand the broader AI coding category, learn both and compare them on one identical repo task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For broader AI upskilling, pair coding-assistant training with the &lt;a href="https://www.coursefacts.com/guides/best-ai-courses-software-engineers-2026" rel="noopener noreferrer"&gt;best AI courses for software engineers&lt;/a&gt;, &lt;a href="https://www.coursefacts.com/guides/best-ai-engineering-courses-developers-2026" rel="noopener noreferrer"&gt;best AI engineering courses&lt;/a&gt;, and &lt;a href="https://www.coursefacts.com/guides/ai-agent-developer-learning-path-2026" rel="noopener noreferrer"&gt;AI agent developer learning path&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistake: treating AI output as authority
&lt;/h2&gt;

&lt;p&gt;The tool is not the reviewer. Whether you use Copilot or Cursor, the durable skill is the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define the task clearly;&lt;/li&gt;
&lt;li&gt;constrain the assistant with repo context;&lt;/li&gt;
&lt;li&gt;ask for tests and failure cases;&lt;/li&gt;
&lt;li&gt;inspect every diff;&lt;/li&gt;
&lt;li&gt;run the local checks;&lt;/li&gt;
&lt;li&gt;reject plausible but unsupported suggestions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI coding assistants reward strong engineering habits. They do not replace them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot is the better default for organizations that want a familiar, GitHub-native AI assistant with lower rollout friction. Cursor is the better default for developers who want an AI-first coding environment with stronger repo-wide and agentic workflows.&lt;/p&gt;

&lt;p&gt;There is no universal winner. The right choice depends on whether you want AI to accelerate your current workflow or reshape the workflow itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources checked
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Docs, &lt;a href="https://docs.github.com/en/copilot" rel="noopener noreferrer"&gt;GitHub Copilot documentation&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;li&gt;GitHub, &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot product page&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;li&gt;Cursor, &lt;a href="https://cursor.com/" rel="noopener noreferrer"&gt;Cursor product page&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;li&gt;Cursor, &lt;a href="https://cursor.com/docs" rel="noopener noreferrer"&gt;Cursor Docs&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.coursefacts.com/guides/github-copilot-vs-cursor-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Kysely vs Drizzle vs Prisma Guide for Type-Safe SQL</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 23 Sep 2026 16:00:40 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/kysely-vs-drizzle-vs-prisma-guide-for-type-safe-sql-4b6d</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/kysely-vs-drizzle-vs-prisma-guide-for-type-safe-sql-4b6d</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/kysely-vs-drizzle-vs-prisma-guide-for-type-safe-sql-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Editor note: This page is retained for historical search paths, but PkgPulse now consolidates this topic around the canonical guide: &lt;a href="https://www.pkgpulse.com/guides/kysely-vs-drizzle-vs-prisma-type-safe-sql-2026" rel="noopener noreferrer"&gt;Kysely vs Drizzle vs Prisma: Type-Safe SQL Guide 2026&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Compare Kysely vs Drizzle vs Prisma Guide for Type-Safe SQL for JavaScript teams, with package risk, migration steps, CI checks, maintainer tradeoffs, and long-term ownership. This final 2026 SEO backlog guide is written for teams making a practical JavaScript package and tooling decision, not for readers who want a vendor brochure. Start with the workflow, constraints, budget model, and switching cost; then test the two or three strongest options against a real scenario.&lt;/p&gt;

&lt;p&gt;The safest answer is usually the choice your team can operate after launch. Prefer clear documentation, portable data, predictable pricing, and a proof of concept that exposes edge cases before the decision becomes hard to reverse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decide from the job to be done first; market popularity is supporting evidence, not the decision.&lt;/li&gt;
&lt;li&gt;Run a small proof of concept with realistic users, permissions, content, data, and failure modes.&lt;/li&gt;
&lt;li&gt;Compare the full year-one cost: setup time, upgrades, support, billing tiers, monitoring, and training.&lt;/li&gt;
&lt;li&gt;Prefer reversible architecture when the category is changing quickly or requirements are still uncertain.&lt;/li&gt;
&lt;li&gt;Document the tradeoffs so future maintainers understand why the choice was made.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Decision Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Best direction&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You need the fastest safe launch&lt;/td&gt;
&lt;td&gt;Pick the option with the clearest default path&lt;/td&gt;
&lt;td&gt;A strong happy path reduces glue code, review time, and onboarding risk.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You expect custom workflows&lt;/td&gt;
&lt;td&gt;Favor the most extensible option&lt;/td&gt;
&lt;td&gt;Extensibility matters once the product moves beyond the demo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You have a small team&lt;/td&gt;
&lt;td&gt;Choose the stack your team can debug&lt;/td&gt;
&lt;td&gt;Familiar operations beat theoretical power under deadline pressure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You serve enterprise or regulated users&lt;/td&gt;
&lt;td&gt;Check permissions, auditability, exports, and support&lt;/td&gt;
&lt;td&gt;Governance gaps become expensive after adoption.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You are still validating demand&lt;/td&gt;
&lt;td&gt;Keep the setup simple and portable&lt;/td&gt;
&lt;td&gt;Early choices should maximize learning speed and preserve optionality.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to Evaluate Kysely vs Drizzle vs Prisma Guide for Type-Safe SQL
&lt;/h2&gt;

&lt;p&gt;A useful evaluation starts with one concrete use case. Write a sentence that names the user, the workflow, the data or content involved, and the failure mode that would hurt most. That sentence should drive every comparison criterion. If a feature does not support the workflow or reduce risk, it belongs below the line.&lt;/p&gt;

&lt;p&gt;Next, map the operating model. Who owns configuration? Who approves changes? Where do credentials, webhooks, imports, exports, billing events, or learner records live? What happens during a vendor outage, a breaking upgrade, or a sudden usage spike? The best option is not the one with every feature; it is the one your team can keep healthy after the initial setup.&lt;/p&gt;

&lt;p&gt;Finally, compare switching cost. Export formats, API standards, repository ownership, content portability, and documentation quality determine how painful a later migration will be. A slightly less powerful tool can still be the better choice when it gives you cleaner control and fewer long-term surprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison Criteria
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fit for the primary workflow
&lt;/h3&gt;

&lt;p&gt;Score each option against the workflow that matters most. If this is a migration, test import and export fidelity. If it is a comparison, implement the smallest real scenario. If it is a learning path, inspect prerequisites, practice depth, assessment quality, and how quickly the learner can apply the skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation and maintenance effort
&lt;/h3&gt;

&lt;p&gt;The first setup is only a fraction of the cost. Review local development, permissions, staging environments, release process, monitoring, support channels, and how clearly errors are documented. Teams often regret tools that look simple in a demo but require undocumented workarounds in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data control and portability
&lt;/h3&gt;

&lt;p&gt;Before committing, identify what data you can export, which formats are supported, and whether important logic lives in files, APIs, dashboards, or provider-only workflows. Portability protects audits, backups, staging, compliance reviews, and future migrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pricing and scaling triggers
&lt;/h3&gt;

&lt;p&gt;Compare cost at launch, at expected usage, and at a stretch-success scenario. Watch for seat creep, usage tiers, add-on modules, storage, premium support, AI usage, and limits that force an upgrade earlier than expected. If pricing is unclear, treat that uncertainty as a real evaluation factor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecosystem and team fit
&lt;/h3&gt;

&lt;p&gt;A technically strong choice can still be wrong if nobody on the team can maintain it. Consider framework fit, examples, community maturity, integrations, and whether future hires or teammates will understand the stack. Ecosystem fit often determines how quickly the team can recover when something breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option Notes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Where it can fit&lt;/th&gt;
&lt;th&gt;What to verify&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kysely&lt;/td&gt;
&lt;td&gt;Strong when its default workflow matches your team&lt;/td&gt;
&lt;td&gt;Verify pricing, exports, governance, support, and migration cost before standardizing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drizzle&lt;/td&gt;
&lt;td&gt;Strong when its default workflow matches your team&lt;/td&gt;
&lt;td&gt;Verify pricing, exports, governance, support, and migration cost before standardizing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prisma&lt;/td&gt;
&lt;td&gt;Strong when its default workflow matches your team&lt;/td&gt;
&lt;td&gt;Verify pricing, exports, governance, support, and migration cost before standardizing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use these notes as starting hypotheses, not final rankings. The winning option changes when your constraints change: a solo founder, a regulated team, a content-heavy product, and an enterprise platform group can all make rationally different choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Evaluation Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Define the core workflow and success metric in one sentence.&lt;/li&gt;
&lt;li&gt;List must-have requirements separately from nice-to-have features.&lt;/li&gt;
&lt;li&gt;Build a small proof of concept with realistic inputs, permissions, and deployment constraints.&lt;/li&gt;
&lt;li&gt;Test error handling, documentation quality, exports, upgrade paths, and support expectations.&lt;/li&gt;
&lt;li&gt;Estimate total cost at launch, expected usage, and a stretch-success scenario.&lt;/li&gt;
&lt;li&gt;Choose the lowest-regret option and document the assumptions behind it.&lt;/li&gt;
&lt;li&gt;Schedule a review after real usage data replaces the initial guess.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;The biggest mistake is choosing by brand recognition alone. Market leaders may be the right answer, but popularity does not prove fit for your product, team, budget, or operating model. The second mistake is ignoring unglamorous details such as billing, audit logs, backups, staging, monitoring, accessibility, and support. Those details rarely show up in launch posts, but they dominate ownership cost.&lt;/p&gt;

&lt;p&gt;Another common mistake is optimizing for a hypothetical future before validating the current need. If two credible options are close, choose the one that helps you ship and learn while keeping migration realistic. You can deepen the architecture once usage proves the investment worthwhile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Related guide: &lt;a href="https://www.pkgpulse.com/guides/20-fastest-growing-npm-packages-2026" rel="noopener noreferrer"&gt;/guides/20-fastest-growing-npm-packages-2026&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Related guide: &lt;a href="https://www.pkgpulse.com/guides/50-most-underrated-npm-packages-2026" rel="noopener noreferrer"&gt;/guides/50-most-underrated-npm-packages-2026&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;Choose Kysely vs Drizzle vs Prisma Guide for Type-Safe SQL when it matches your real workflow, your team's maintenance capacity, and your tolerance for lock-in. A good decision should make the next month easier without making the next year fragile. Treat the proof of concept, cost model, and migration plan as required parts of the decision rather than cleanup work after the fact.&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/kysely-vs-drizzle-vs-prisma-guide-for-type-safe-sql-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>MCP for Python Developers Course Guide 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 23 Sep 2026 16:00:32 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/mcp-for-python-developers-course-guide-2026-3329</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/mcp-for-python-developers-course-guide-2026-3329</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/mcp-for-python-developers-course-guide-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Editorial status
&lt;/h2&gt;

&lt;p&gt;This legacy page for MCP for Python Developers Course Guide remains noindex while CourseFacts consolidates overlapping course and platform coverage. It is retained for route continuity, not as a current ranking or purchase recommendation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to evaluate MCP for Python Developers Course Guide
&lt;/h2&gt;

&lt;p&gt;To evaluate MCP for Python Developers Course Guide, compare the exact syllabus, prerequisites, assessed projects, instructor feedback, study schedule, certificate rules, and current provider terms. Use a short sample or audit option before paying when one is available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before enrolling
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;verify the live price, renewal date, cancellation path, and refund policy;&lt;/li&gt;
&lt;li&gt;distinguish a completion certificate from an accredited credential or issuer-controlled certification;&lt;/li&gt;
&lt;li&gt;choose the option that requires independent practice, not only guided completion;&lt;/li&gt;
&lt;li&gt;avoid treating platform popularity as evidence of fit or career outcomes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related CourseFacts guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/ai-agent-developer-learning-path-2026" rel="noopener noreferrer"&gt;AI Agent Developer Learning Path 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/frontend-masters-vs-zero-to-mastery-2026" rel="noopener noreferrer"&gt;/guides/frontend-masters-vs-zero-to-mastery-2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/best-agentic-ai-courses-2026" rel="noopener noreferrer"&gt;/guides/best-agentic-ai-courses-2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.coursefacts.com/guides/mcp-for-python-developers-course-guide-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>React Native MMKV vs AsyncStorage vs Expo SecureStore: 2026 Storage Decision Guide</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 16 Sep 2026 21:40:21 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/react-native-mmkv-vs-asyncstorage-vs-expo-securestore-2026-storage-decision-guide-30jo</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/react-native-mmkv-vs-asyncstorage-vs-expo-securestore-2026-storage-decision-guide-30jo</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/react-native-mmkv-vs-async-storage-vs-expo-secure-store-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;For most React Native apps in 2026, the decision is not one winner. Use &lt;strong&gt;react-native-mmkv&lt;/strong&gt; for fast app state, preferences, feature flags, small caches, and Zustand/Jotai persistence; use &lt;strong&gt;expo-secure-store&lt;/strong&gt; for auth tokens, refresh tokens, API keys, and other small secrets; keep &lt;strong&gt;AsyncStorage&lt;/strong&gt; only when you need the simplest async key-value baseline, Expo Go compatibility, or a low-risk migration path for an older app.&lt;/p&gt;

&lt;p&gt;The practical rule is: &lt;strong&gt;MMKV for speed, SecureStore for secrets, AsyncStorage for compatibility.&lt;/strong&gt; MMKV's official README describes fully synchronous calls, multiple instances, encryption support, JSI/NitroModule bindings, and a published benchmark of roughly 30x faster than AsyncStorage. AsyncStorage's current official GitHub docs describe it as asynchronous, unencrypted, persistent key-value storage and note that v3 adds &lt;code&gt;createAsyncStorage&lt;/code&gt; scoped storage while preserving the legacy default export. Expo SecureStore's docs describe encrypted local key-value storage backed by platform secure storage on iOS and Android, but warn that large payloads can be rejected and that roughly 2 KB iOS limits have existed historically.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Storage choice&lt;/th&gt;
&lt;th&gt;Best use&lt;/th&gt;
&lt;th&gt;Do not use it for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;react-native-mmkv&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast reads/writes, render-adjacent preferences, persisted client state, feature flags, offline queues&lt;/td&gt;
&lt;td&gt;Raw secrets unless the encryption key is protected outside the JS bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AsyncStorage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple async persistence, old codebases, Expo Go-friendly examples, compatibility-first storage&lt;/td&gt;
&lt;td&gt;Performance-critical hydration or sensitive credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;expo-secure-store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tokens, refresh tokens, API keys, biometric-gated secrets, device-bound keys&lt;/td&gt;
&lt;td&gt;Large JSON caches, bulk offline state, hot render-path reads&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choose MMKV for user-visible responsiveness.&lt;/strong&gt; Synchronous reads are useful when a theme, onboarding flag, cart, or navigation state needs to be available before rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose SecureStore for credentials.&lt;/strong&gt; Tokens belong in platform secure storage, not in AsyncStorage and not in a hardcoded MMKV encryption key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose AsyncStorage when compatibility beats speed.&lt;/strong&gt; It is still a useful baseline for simple async storage and incremental migrations, especially when existing libraries already expect its API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not treat MMKV encryption as a token-storage replacement by itself.&lt;/strong&gt; If the key is embedded in JavaScript, the protection is weak. Store the MMKV key in SecureStore if you encrypt larger sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep large values out of SecureStore.&lt;/strong&gt; Expo explicitly warns that large payloads can be rejected by the underlying platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update older AsyncStorage examples carefully.&lt;/strong&gt; Newer official docs introduce &lt;code&gt;createAsyncStorage("database-name")&lt;/code&gt;; the default export remains a backward-compatible singleton for v2-style code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The fast decision tree
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Are you storing auth tokens, refresh tokens, API keys, or private keys?
  → Use expo-secure-store.

Are you storing theme, locale, flags, persisted Zustand/Jotai state, cart state, or small offline queues?
  → Use react-native-mmkv.

Are you in Expo Go, maintaining old AsyncStorage code, or integrating a library that only accepts async storage?
  → Use AsyncStorage, then migrate hot paths to MMKV later.

Are you storing large files, photos, blobs, SQLite-sized data, or hundreds of MB of cache?
  → Use expo-file-system, SQLite, WatermelonDB, Realm, or a real database instead.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AsyncStorage&lt;/th&gt;
&lt;th&gt;react-native-mmkv&lt;/th&gt;
&lt;th&gt;expo-secure-store&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API shape&lt;/td&gt;
&lt;td&gt;Promise-based async key-value API&lt;/td&gt;
&lt;td&gt;Synchronous key-value API plus hooks&lt;/td&gt;
&lt;td&gt;Promise-based secure key-value API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Official positioning&lt;/td&gt;
&lt;td&gt;Asynchronous, unencrypted persistent storage&lt;/td&gt;
&lt;td&gt;Fast direct native C++ bindings for React Native&lt;/td&gt;
&lt;td&gt;Encrypted local key-value storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Compatibility and simple persistence&lt;/td&gt;
&lt;td&gt;Performance-sensitive app state&lt;/td&gt;
&lt;td&gt;Small sensitive secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expo support&lt;/td&gt;
&lt;td&gt;Works in Expo projects and Expo Go-style examples&lt;/td&gt;
&lt;td&gt;Expo install plus prebuild/development build because it is a native module&lt;/td&gt;
&lt;td&gt;Included in Expo Go, with caveats for &lt;code&gt;requireAuthentication&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption&lt;/td&gt;
&lt;td&gt;No built-in encryption&lt;/td&gt;
&lt;td&gt;MMKV file encryption available; key management is your responsibility&lt;/td&gt;
&lt;td&gt;Uses platform secure storage on iOS/Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple stores&lt;/td&gt;
&lt;td&gt;v3 supports scoped storage via &lt;code&gt;createAsyncStorage&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Multiple instances via IDs&lt;/td&gt;
&lt;td&gt;Separate keys, not multiple high-volume stores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data types&lt;/td&gt;
&lt;td&gt;Strings; serialize objects manually&lt;/td&gt;
&lt;td&gt;Strings, booleans, numbers, buffers; serialize objects manually&lt;/td&gt;
&lt;td&gt;Strings/values intended to stay small&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Render-path reads&lt;/td&gt;
&lt;td&gt;Avoid; async hydration can cause loading states&lt;/td&gt;
&lt;td&gt;Good fit; synchronous reads avoid &lt;code&gt;await&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Avoid; secure storage calls are async and slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration difficulty&lt;/td&gt;
&lt;td&gt;Baseline/legacy option&lt;/td&gt;
&lt;td&gt;Requires native setup and call-site updates&lt;/td&gt;
&lt;td&gt;Requires async token-access flow and error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source snapshot checked 2026-06-15&lt;/td&gt;
&lt;td&gt;npm &lt;code&gt;3.1.1&lt;/code&gt;; MIT; large package because docs/build artifacts are published&lt;/td&gt;
&lt;td&gt;npm &lt;code&gt;4.3.1&lt;/code&gt;; MIT; small package metadata footprint&lt;/td&gt;
&lt;td&gt;npm &lt;code&gt;56.0.4&lt;/code&gt;; MIT; Expo SDK-aligned package&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  AsyncStorage: compatibility baseline, not the performance choice
&lt;/h2&gt;

&lt;p&gt;AsyncStorage is still worth knowing because a lot of React Native libraries, examples, and older apps use it. The current official README describes it as an asynchronous, unencrypted, persistent key-value storage solution for React Native. Its API is easy to understand: store strings with &lt;code&gt;setItem&lt;/code&gt;, read them with &lt;code&gt;getItem&lt;/code&gt;, and serialize objects yourself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@react-native-async-storage/async-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&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;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&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;userJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userJson&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userJson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multiSet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;locale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notifications&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&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;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multiGet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;locale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What's changed in current AsyncStorage docs
&lt;/h3&gt;

&lt;p&gt;Older guides usually show only the default export. Current official GitHub docs also document &lt;code&gt;createAsyncStorage&lt;/code&gt;, which creates a named scoped storage instance. That matters for apps that want separate databases per user, workspace, or feature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createAsyncStorage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@react-native-async-storage/async-storage&lt;/span&gt;&lt;span class="dl"&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;userStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAsyncStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-1234&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preferences&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&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;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preferences&lt;/span&gt;&lt;span class="dl"&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;preferences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default export is still useful for backward-compatible v2-style integrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@react-native-async-storage/async-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;legacy-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When AsyncStorage is still the right choice
&lt;/h3&gt;

&lt;p&gt;Use AsyncStorage when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your app already uses it and storage is not on a hot path;&lt;/li&gt;
&lt;li&gt;you need a simple Promise-based adapter for libraries such as Redux Persist or Zustand's async storage adapter;&lt;/li&gt;
&lt;li&gt;Expo Go compatibility matters more than startup speed;&lt;/li&gt;
&lt;li&gt;you want to migrate gradually before introducing a native MMKV dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not use AsyncStorage for auth tokens or secrets. The official docs call it unencrypted, and Expo's own data-storage guidance describes AsyncStorage as a good choice for data that does not need encryption, such as preferences or app state.&lt;/p&gt;




&lt;h2&gt;
  
  
  react-native-mmkv: the default for fast local app state
&lt;/h2&gt;

&lt;p&gt;react-native-mmkv is the performance option. The official README describes fully synchronous calls, no async/await or promises, direct native C++ bindings, encryption support, multiple instances, JSI/NitroModule support, and a benchmark of roughly 30x faster than AsyncStorage.&lt;/p&gt;

&lt;p&gt;Current MMKV examples use &lt;code&gt;createMMKV&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMMKV&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-mmkv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMMKV&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;launchCount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onboardingComplete&lt;/span&gt;&lt;span class="dl"&gt;"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&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;launchCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;launchCount&lt;/span&gt;&lt;span class="dl"&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;onboardingComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onboardingComplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&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;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAllKeys&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Namespaced MMKV instances
&lt;/h3&gt;

&lt;p&gt;MMKV is a strong fit when you want to isolate app-wide settings, per-user state, and cache-like data without making every caller think about file paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMMKV&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-mmkv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMMKV&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMMKV&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cache-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMMKV&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-1234-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;cacheStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MMKV with Zustand persist
&lt;/h3&gt;

&lt;p&gt;MMKV pairs well with Zustand because the storage adapter can hydrate synchronously. That removes an entire class of "wait for storage before rendering" code in preferences, carts, and feature-flag stores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zustand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createJSONStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;persist&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zustand/middleware&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CartItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CartState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CartItem&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CartItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&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;mmkvStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createJSONStorage&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCartStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CartState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;
  &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="na"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&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;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cart-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mmkvStorage&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;h3&gt;
  
  
  MMKV encryption and key management
&lt;/h3&gt;

&lt;p&gt;MMKV supports encrypted storage, but encryption is only as strong as the key-management pattern. If the encryption key is hardcoded in the JavaScript bundle, a motivated attacker can extract it. A safer pattern is to generate a random key, keep that key in SecureStore, and use it to initialize or encrypt MMKV.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expo-secure-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMMKV&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-mmkv&lt;/span&gt;&lt;span class="dl"&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;MMKV_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mmkv-encryption-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOrCreateEncryptionKey&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;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MMKV_KEY&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;existing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;existing&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateRandomKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Use expo-random, react-native-get-random-values, or your approved crypto helper.&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MMKV_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createEncryptedStorage&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;encryptionKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getOrCreateEncryptionKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createMMKV&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;encrypted-app-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;encryptionKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;encryptionType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-256&lt;/span&gt;&lt;span class="dl"&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;Use this for larger sensitive local datasets where SecureStore is too small or too slow. For normal auth tokens, SecureStore alone is simpler and easier to audit.&lt;/p&gt;




&lt;h2&gt;
  
  
  expo-secure-store: the credential store
&lt;/h2&gt;

&lt;p&gt;Expo SecureStore is the right default for auth tokens, refresh tokens, API keys, private keys, and other small values that should not be stored in plaintext. The Expo docs describe it as a way to encrypt and securely store key-value pairs locally on the device. On Android, values are stored in &lt;code&gt;SharedPreferences&lt;/code&gt; encrypted with Android's Keystore system. On iOS, values are stored using Keychain services as &lt;code&gt;kSecClassGenericPassword&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expo-secure-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refresh_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refresh_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SecureStore options worth caring about
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;refresh_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;keychainAccessible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WHEN_UNLOCKED_THIS_DEVICE_ONLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private_key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;requireAuthentication&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="na"&gt;authenticationPrompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unlock your key&lt;/span&gt;&lt;span class="dl"&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;Use &lt;code&gt;WHEN_UNLOCKED_THIS_DEVICE_ONLY&lt;/code&gt; when a credential should stay tied to the current device rather than moving through backup/restore flows. Use &lt;code&gt;requireAuthentication&lt;/code&gt; only after testing the actual Expo/client environment because Expo documents an Expo Go caveat for biometric authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  SecureStore is not a cache
&lt;/h3&gt;

&lt;p&gt;SecureStore is for small secrets, not large offline payloads. Expo warns that large payloads can be rejected by the underlying platform and notes that some iOS releases historically refused values above roughly 2048 bytes. If you need to persist a large object securely, store a SecureStore-protected encryption key and put the encrypted payload in MMKV, SQLite, or a file/database layer designed for larger values.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to store where
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Access token
  → expo-secure-store

Refresh token
  → expo-secure-store, often with WHEN_UNLOCKED_THIS_DEVICE_ONLY

MMKV encryption key
  → expo-secure-store

Theme, locale, onboarding flag
  → react-native-mmkv

Persisted Zustand/Jotai state
  → react-native-mmkv

Feature flags and remote-config cache
  → react-native-mmkv

Small API response cache
  → react-native-mmkv if read often; AsyncStorage if compatibility matters

Draft form state
  → react-native-mmkv

Large files, images, SQLite-like data, document caches
  → expo-file-system, SQLite, Realm, WatermelonDB, or another data store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Do not stretch key-value storage into a local database
&lt;/h2&gt;

&lt;p&gt;MMKV, AsyncStorage, and SecureStore are all key-value tools. They are not replacements for an offline relational store, document cache, or sync engine. If the data model has queries, relationships, conflict resolution, attachments, or hundreds of rows, route that decision to &lt;a href="https://www.pkgpulse.com/guides/expo-sqlite-vs-watermelondb-vs-realm-react-native-local-2026" rel="noopener noreferrer"&gt;Expo SQLite vs WatermelonDB vs Realm&lt;/a&gt; instead of hiding a database in serialized JSON strings.&lt;/p&gt;

&lt;p&gt;Use the storage trio this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SecureStore&lt;/strong&gt; keeps the credential or encryption key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MMKV&lt;/strong&gt; keeps fast UI/session state and small encrypted payloads when a SecureStore-protected key is available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AsyncStorage&lt;/strong&gt; keeps compatibility data while you migrate older async adapters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite, Realm, WatermelonDB, files, or object storage&lt;/strong&gt; keep real offline data and large caches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration strategy: AsyncStorage to MMKV
&lt;/h2&gt;

&lt;p&gt;The safest production migration is a one-time copy plus a completion flag. Do not replace every &lt;code&gt;await AsyncStorage.getItem&lt;/code&gt; call blindly and hope the app behaves the same. AsyncStorage is async; MMKV is sync. Hydration timing changes, which is usually a benefit but can expose assumptions in startup code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@react-native-async-storage/async-storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMMKV&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-mmkv&lt;/span&gt;&lt;span class="dl"&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;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMMKV&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;MIGRATED_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;async-storage-migrated-v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;migrateAsyncStorageToMMKV&lt;/span&gt;&lt;span class="p"&gt;()&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;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIGRATED_KEY&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAllKeys&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;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multiGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&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;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&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="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIGRATED_KEY&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the migration early in app startup, then update call sites deliberately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AsyncStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep a rollback window. For the first release, copy values into MMKV and leave AsyncStorage intact. After production telemetry shows the migration is stable, ship a second release that removes the old AsyncStorage writes and clears legacy keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security model: what "secure" means here
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AsyncStorage is unencrypted.&lt;/strong&gt; It is fine for non-sensitive preferences and app state, but not for credentials, tokens, or regulated personal data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MMKV can encrypt its storage file.&lt;/strong&gt; That protects the file at rest, but only if the key is protected. A hardcoded JavaScript key is not enough. A SecureStore-backed key is a stronger pattern for larger encrypted local datasets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SecureStore delegates to platform secure storage.&lt;/strong&gt; That is the best fit for secrets, but it comes with async access, platform-specific behavior, and size limits. Design token access around startup/session boundaries instead of calling SecureStore repeatedly during render.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Native New Architecture implications
&lt;/h2&gt;

&lt;p&gt;The New Architecture strengthens the MMKV case because MMKV is built around direct native bindings rather than the old serialized bridge pattern. Its synchronous reads are most valuable for values needed immediately: theme, language, feature flags, session hints, and persisted UI state.&lt;/p&gt;

&lt;p&gt;AsyncStorage remains async even when the app runs on newer React Native architecture. That does not make it bad; it means you should keep it away from hot render paths. SecureStore is async by design because secure platform storage involves OS-level calls and optional authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source notes
&lt;/h2&gt;

&lt;p&gt;Sources checked on 2026-06-15:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react-native-mmkv official GitHub README: &lt;code&gt;https://github.com/mrousavy/react-native-mmkv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;react-native-mmkv npm registry metadata: &lt;code&gt;https://registry.npmjs.org/react-native-mmkv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AsyncStorage official GitHub README and docs source: &lt;code&gt;https://github.com/react-native-async-storage/async-storage&lt;/code&gt;, especially &lt;code&gt;docs/api/usage.md&lt;/code&gt; and &lt;code&gt;docs/faq.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AsyncStorage npm registry metadata: &lt;code&gt;https://registry.npmjs.org/@react-native-async-storage%2fasync-storage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expo SecureStore docs: &lt;code&gt;https://docs.expo.dev/versions/latest/sdk/securestore/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expo data-storage guidance: &lt;code&gt;https://docs.expo.dev/develop/user-interface/store-data/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One older AsyncStorage public docs path (&lt;code&gt;react-native-async-storage.github.io/async-storage/&lt;/code&gt;) returned 404 during refresh, so this guide cites the maintained GitHub source/docs and package registry metadata instead of relying on that stale URL.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Related: &lt;a href="https://www.pkgpulse.com/guides/expo-sqlite-vs-watermelondb-vs-realm-react-native-local-2026" rel="noopener noreferrer"&gt;Expo SQLite vs WatermelonDB vs Realm&lt;/a&gt; for offline databases, &lt;a href="https://www.pkgpulse.com/guides/zustand-vs-jotai-vs-nanostores-micro-state-management-2026" rel="noopener noreferrer"&gt;Zustand vs Jotai vs Nano Stores&lt;/a&gt; for the state layer that often persists into MMKV or AsyncStorage, &lt;a href="https://www.pkgpulse.com/guides/gluestack-ui-vs-react-native-paper-vs-unistyles-react-2026" rel="noopener noreferrer"&gt;Gluestack UI vs React Native Paper vs Unistyles&lt;/a&gt; for React Native UI stack decisions, and &lt;a href="https://www.pkgpulse.com/guides/nativewind-vs-tamagui-vs-twrnc-react-native-styling-2026" rel="noopener noreferrer"&gt;NativeWind vs Tamagui vs twrnc&lt;/a&gt; for styling choices in the same app architecture.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See also: &lt;a href="https://www.pkgpulse.com/compare/react-vs-vue" rel="noopener noreferrer"&gt;React vs Vue&lt;/a&gt; and &lt;a href="https://www.pkgpulse.com/compare/react-vs-svelte" rel="noopener noreferrer"&gt;React vs Svelte&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/react-native-mmkv-vs-async-storage-vs-expo-secure-store-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Codex CLI Course Guide 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 16 Sep 2026 21:40:11 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/codex-cli-course-guide-2026-5bd0</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/codex-cli-course-guide-2026-5bd0</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/codex-cli-course-guide-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Choose OpenAI Codex/Codex CLI resources without confusing them with general OpenAI API courses.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; Treat Codex CLI as terminal-agent training, not a generic OpenAI API course. Start with OpenAI’s Codex learning hub and openai/codex repository, then choose any paid course only if it teaches scoped tasks, command safety, diff review, tests, and rollback.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR verdict
&lt;/h2&gt;

&lt;p&gt;Treat Codex CLI as terminal-agent training, not a generic OpenAI API course. Start with OpenAI’s Codex learning hub and openai/codex repository, then choose any paid course only if it teaches scoped tasks, command safety, diff review, tests, and rollback.&lt;/p&gt;

&lt;p&gt;This refresh intentionally does not quote live prices, ratings, enrollment counts, or certificate terms from the retained Coursera page. Udemy cards remain excluded because this packet retains no verified Udemy source.&lt;/p&gt;

&lt;p&gt;Use this guide to evaluate Codex CLI practice, not as a promise that a course completion signal will produce a job or salary increase, academic credit, or an employer-recognized credential. The durable outcome is a tested terminal workflow with a reviewable patch and clear approval choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this guide is for
&lt;/h2&gt;

&lt;p&gt;This guide is for developers who want structured practice using Codex from repository discovery through implementation and verification. Compare training by shell safety, plan quality, diff review, test execution, and recovery from failed commands—not by marketplace prominence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways and Quick Picks by Learner Goal
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Learner goal&lt;/th&gt;
&lt;th&gt;Best starting option&lt;/th&gt;
&lt;th&gt;What to verify&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Understand current Codex positioning&lt;/td&gt;
&lt;td&gt;OpenAI Codex learning hub&lt;/td&gt;
&lt;td&gt;Primary source for the workflow and product framing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learn the CLI surface&lt;/td&gt;
&lt;td&gt;openai/codex repository&lt;/td&gt;
&lt;td&gt;Use README and docs to understand installation, commands, configuration, and limitations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build terminal-agent habits&lt;/td&gt;
&lt;td&gt;Project tutorial or course&lt;/td&gt;
&lt;td&gt;Must include planning, file edits, tests, and review in a real repo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learn adjacent agent APIs&lt;/td&gt;
&lt;td&gt;OpenAI Agents SDK docs&lt;/td&gt;
&lt;td&gt;Useful for distinguishing coding-agent workflow from app-agent SDK development.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  At-a-Glance Course Fit Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Why it works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CLI-first developer&lt;/td&gt;
&lt;td&gt;Codex CLI project course&lt;/td&gt;
&lt;td&gt;Best if you already use terminal, Git, and tests daily.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI API learner&lt;/td&gt;
&lt;td&gt;OpenAI API/Agents course first&lt;/td&gt;
&lt;td&gt;Do not confuse app development APIs with repo-coding workflow.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team pilot&lt;/td&gt;
&lt;td&gt;Internal exercise on one repo task&lt;/td&gt;
&lt;td&gt;Measure review time, test pass rate, and rollback clarity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Beginner programmer&lt;/td&gt;
&lt;td&gt;Language/framework course first&lt;/td&gt;
&lt;td&gt;Codex helps reviewable developers; it does not replace fundamentals.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Skill Outcomes: What the Curriculum Must Prove
&lt;/h2&gt;

&lt;p&gt;A useful course for this topic should make the learner practice the work, not merely name the tools. Before enrolling, look for evidence of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a current syllabus or module list that matches the 2026 tool surface;&lt;/li&gt;
&lt;li&gt;hands-on projects in a real repository, notebook, workflow, or analysis artifact;&lt;/li&gt;
&lt;li&gt;explicit review checkpoints such as tests, evals, citations, traces, or Git diffs;&lt;/li&gt;
&lt;li&gt;instructor updates when the underlying product or provider changes;&lt;/li&gt;
&lt;li&gt;clear prerequisites so beginners are not sold an advanced workflow too early;&lt;/li&gt;
&lt;li&gt;conservative credential language that distinguishes completion proof from formal academic recognition.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practice Project Evidence to Demand
&lt;/h2&gt;

&lt;p&gt;A strong Codex CLI course should end with a small production-like change: open an issue, create a branch, ask for a plan, edit files, run a focused test, fix one failure, inspect the diff, and write a final handoff.&lt;/p&gt;

&lt;p&gt;A credible Codex CLI course should produce a bounded repository change, preserve the command and approval trail, run the project's checks, and leave a patch another developer can review. A prompt-only terminal demo is orientation rather than evidence of autonomous coding workflow skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing, refunds, and certificates
&lt;/h2&gt;

&lt;p&gt;Course platform terms move faster than evergreen guide pages. Before paying, open the official platform page and confirm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;current price or subscription requirement;&lt;/li&gt;
&lt;li&gt;whether auditing, trials, or free access are available;&lt;/li&gt;
&lt;li&gt;what a completion certificate does and does not represent;&lt;/li&gt;
&lt;li&gt;refund, cancellation, or renewal terms;&lt;/li&gt;
&lt;li&gt;whether the course was recently updated for the tool versions you plan to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CourseFacts uses plain outbound links in this guide. No affiliate or sponsored relationship is implied unless a link is explicitly labeled that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source-backed claim map
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Claim type&lt;/th&gt;
&lt;th&gt;What this guide relies on&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;th&gt;Visible caveat needed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;comparison&lt;/td&gt;
&lt;td&gt;Codex CLI course intent is terminal-agent coding workflow, distinct from general OpenAI API development&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;curriculum&lt;/td&gt;
&lt;td&gt;OpenAI Codex learning resources and the openai/codex repository are primary sources for current Codex positioning and workflow language&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;availability_freshness&lt;/td&gt;
&lt;td&gt;The retained Coursera course page returned 200; this page avoids pricing, certificate, rating, or availability claims without a fresh page-level check&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Methodology: How We Selected This Wave
&lt;/h2&gt;

&lt;p&gt;This page owns the Codex CLI training intent in the 2026 AI coding set and is narrower than the general agent-development guides. OpenAI's Codex learning page, repository, Agents SDK, and the retained Coursera course define the evidence base.&lt;/p&gt;

&lt;p&gt;Official OpenAI material anchors Codex behavior, and the retained Coursera page is the only marketplace course source used here. Verify its live syllabus, price, access, certificate, and refund terms before purchase; Udemy cards remain excluded until a specific page is sourced and checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/best-openai-api-courses-2026" rel="noopener noreferrer"&gt;Best Openai API Courses 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/best-ai-developer-api-courses-2026" rel="noopener noreferrer"&gt;Best AI Developer API Courses 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/best-claude-code-courses-2026" rel="noopener noreferrer"&gt;Best Claude Code Courses 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursefacts.com/guides/best-cursor-courses-2026" rel="noopener noreferrer"&gt;Best Cursor Courses 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Codex CLI the same as learning the OpenAI API?
&lt;/h3&gt;

&lt;p&gt;No. Codex CLI is about agent-assisted coding in a repository; OpenAI API courses are about building applications that call models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I rely on marketplace Codex courses?
&lt;/h3&gt;

&lt;p&gt;Only after checking the live page and syllabus. The field changes quickly, so official sources and current repo docs should anchor the path.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest first exercise?
&lt;/h3&gt;

&lt;p&gt;Use a non-critical repository task with tests and a clean branch. Never start with secrets, migrations, or broad rewrites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developers.openai.com/learn/codex" rel="noopener noreferrer"&gt;OpenAI Codex learning hub&lt;/a&gt; (OpenAI, accessed 2026-09-07). Official current Codex learning surface; this guide keeps a CLI-specific scope.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;openai/codex GitHub repository&lt;/a&gt; (OpenAI, accessed 2026-09-07). Use for repo/product freshness only; volatile stars and release dates are intentionally excluded.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.coursera.org/learn/introduction-to-openai-codex" rel="noopener noreferrer"&gt;Coursera Introduction to OpenAI Codex&lt;/a&gt; (Coursera, accessed 2026-09-07). The current one-module course page supports curriculum and certificate availability but no stable price or guaranteed subscription inclusion.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openai.github.io/openai-agents-python/" rel="noopener noreferrer"&gt;OpenAI Agents SDK documentation&lt;/a&gt; (OpenAI, accessed 2026-07-14). Official agent SDK docs, not a course catalog.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.coursera.org/courseraplus" rel="noopener noreferrer"&gt;Coursera Plus&lt;/a&gt; (Coursera, accessed 2026-09-07). Official platform-level pricing and certificate terms; prices vary by geography, and this does not prove that the individual course is included.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.coursera.org/about/terms#refund-and-cancellation-policy" rel="noopener noreferrer"&gt;Coursera Refund and Cancellation Policy&lt;/a&gt; (Coursera, accessed 2026-09-07). Current policy for one-time and subscription purchases; offer, checkout, marketplace, and jurisdiction-specific terms can differ.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.coursefacts.com/guides/codex-cli-course-guide-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Tauri vs Electron vs Neutralino 2026: JavaScript Desktop App Decision Guide</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 08 Jul 2026 16:01:30 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/tauri-vs-electron-vs-neutralino-2026-javascript-desktop-app-decision-guide-2kaf</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/tauri-vs-electron-vs-neutralino-2026-javascript-desktop-app-decision-guide-2kaf</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/tauri-vs-electron-vs-neutralino-desktop-apps-javascript-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;For the query &lt;strong&gt;"Electron vs Tauri vs Neutralino"&lt;/strong&gt;, the right answer is not one winner. Pick &lt;strong&gt;Electron&lt;/strong&gt; when you need the most mature desktop runtime, predictable Chromium rendering, Node.js in the main process, and the widest packaging/updater ecosystem. Pick &lt;strong&gt;Tauri&lt;/strong&gt; when installer size, memory use, and a smaller attack surface matter more than a pure-JavaScript backend. Pick &lt;strong&gt;Neutralino&lt;/strong&gt; when the app is a lightweight utility and you only need a thin native window, tray, storage, and file/OS APIs around an existing web UI.&lt;/p&gt;

&lt;p&gt;Do not use this guide as a broad desktop-framework roundup. If you are comparing Flutter, Qt, .NET MAUI, native Swift/WinUI, or mobile targets too, start with &lt;a href="https://www.pkgpulse.com/guides/best-desktop-app-frameworks-2026" rel="noopener noreferrer"&gt;Best Desktop App Frameworks 2026&lt;/a&gt;. This page stays focused on the three JavaScript/WebView-style choices: &lt;strong&gt;Tauri vs Electron vs Neutralino&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast Decision Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision point&lt;/th&gt;
&lt;th&gt;Electron&lt;/th&gt;
&lt;th&gt;Tauri&lt;/th&gt;
&lt;th&gt;Neutralino&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best default for&lt;/td&gt;
&lt;td&gt;Mature cross-platform products&lt;/td&gt;
&lt;td&gt;Small, secure-feeling desktop apps&lt;/td&gt;
&lt;td&gt;Tiny utilities and wrappers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rendering engine&lt;/td&gt;
&lt;td&gt;Bundled Chromium&lt;/td&gt;
&lt;td&gt;OS WebView: WebView2 on Windows, WebKit/WKWebView on macOS/Linux variants&lt;/td&gt;
&lt;td&gt;OS WebView&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend/runtime model&lt;/td&gt;
&lt;td&gt;Node.js main process plus Chromium renderer&lt;/td&gt;
&lt;td&gt;Rust backend commands plus web frontend&lt;/td&gt;
&lt;td&gt;Built-in native API server; optional external extensions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package size posture&lt;/td&gt;
&lt;td&gt;Largest, because Chromium ships with the app&lt;/td&gt;
&lt;td&gt;Usually much smaller; WebView is supplied by the OS&lt;/td&gt;
&lt;td&gt;Usually smallest for simple apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory posture&lt;/td&gt;
&lt;td&gt;Highest baseline&lt;/td&gt;
&lt;td&gt;Lower baseline for comparable simple apps&lt;/td&gt;
&lt;td&gt;Lowest for simple wrappers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native API depth&lt;/td&gt;
&lt;td&gt;Deep and battle-tested&lt;/td&gt;
&lt;td&gt;Strong through Rust commands and official/community plugins&lt;/td&gt;
&lt;td&gt;Useful but intentionally smaller&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security posture&lt;/td&gt;
&lt;td&gt;Good when hardened, but Node/IPC mistakes are common&lt;/td&gt;
&lt;td&gt;Strong by default when permissions and commands are scoped&lt;/td&gt;
&lt;td&gt;Token/allow-list model; smaller surface, smaller ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-update story&lt;/td&gt;
&lt;td&gt;Mature third-party tooling such as electron-builder/electron-updater&lt;/td&gt;
&lt;td&gt;Official updater plugin with signed updates&lt;/td&gt;
&lt;td&gt;Manual/custom update flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team fit&lt;/td&gt;
&lt;td&gt;JavaScript/Node teams, complex desktop apps&lt;/td&gt;
&lt;td&gt;Teams willing to own Rust and WebView testing&lt;/td&gt;
&lt;td&gt;Teams shipping simple utilities fast&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  2026 source snapshot
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package/docs source checked 2026-06-15&lt;/th&gt;
&lt;th&gt;Current evidence&lt;/th&gt;
&lt;th&gt;Use it for&lt;/th&gt;
&lt;th&gt;Caveat&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Electron docs + &lt;code&gt;electron@42.4.0&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Mature Chromium/Node runtime and packaging ecosystem&lt;/td&gt;
&lt;td&gt;Complex JS desktop products&lt;/td&gt;
&lt;td&gt;Largest artifact/memory posture among the three&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tauri 2 docs + &lt;code&gt;@tauri-apps/api@2.11.0&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Tauri 2.x command/plugin model and updater/security docs&lt;/td&gt;
&lt;td&gt;Small artifacts and scoped native commands&lt;/td&gt;
&lt;td&gt;Rust ownership and OS-WebView QA are real costs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neutralino docs + &lt;code&gt;@neutralinojs/neu@11.7.2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Minimal wrapper and compact native API overview&lt;/td&gt;
&lt;td&gt;Lightweight utilities and wrappers&lt;/td&gt;
&lt;td&gt;Smaller ecosystem and manual/custom update expectations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Electron wins on maturity and rendering consistency.&lt;/strong&gt; It ships Chromium, so CSS/JS behavior is predictable across platforms, and the packaging ecosystem is deep.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tauri wins when bundle size, idle memory, and permission scoping matter.&lt;/strong&gt; Tauri 2.x pairs a web frontend with Rust commands and OS WebViews, so you trade a heavier toolchain for smaller app artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neutralino is not a Tauri clone.&lt;/strong&gt; It is a minimal WebView wrapper with a compact native API surface; it is best for utilities, internal tools, launchers, and dashboards that do not need a deep backend runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototype the operational surface before choosing.&lt;/strong&gt; File permissions, tray/menu behavior, code signing, deep links, crash reporting, and auto-updates usually expose the real framework fit faster than hello-world bundle numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep broad framework intent separate.&lt;/strong&gt; Use this guide for the three-way JavaScript desktop decision; use the broader &lt;a href="https://www.pkgpulse.com/guides/best-desktop-app-frameworks-2026" rel="noopener noreferrer"&gt;desktop framework roundup&lt;/a&gt; when native UI stacks are in scope.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Changed Since Older Electron vs Tauri Advice
&lt;/h2&gt;

&lt;p&gt;The desktop-app decision used to be framed as "Electron is big, Tauri is small." That is still directionally true, but it is not enough for a 2026 production decision.&lt;/p&gt;

&lt;p&gt;Electron remains the proven runtime for apps that need a bundled browser, a Node.js main process, mature OS integrations, and packaging/updater tooling that many teams already understand. Tauri 2.x is now mature enough that teams can seriously choose it for production desktop apps, but they must accept Rust commands, OS-WebView variation, and a different permissions model. Neutralino stays deliberately narrow: it is attractive when the product is mostly a local web UI with a few native operations, not when you need a full application platform.&lt;/p&gt;

&lt;p&gt;The better comparison is therefore:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Runtime control:&lt;/strong&gt; bundled Chromium + Node.js, Rust command layer, or minimal native API bridge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution cost:&lt;/strong&gt; app size, signing/notarization, installers, update channels, and support burden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security model:&lt;/strong&gt; renderer isolation, IPC/command boundaries, permissions, update signing, and dependency exposure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web compatibility:&lt;/strong&gt; one Chromium version everywhere vs platform WebView differences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team skill:&lt;/strong&gt; Node/Electron experience, Rust ownership, or a small wrapper around a web app.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Electron: Choose the Proven Desktop Runtime
&lt;/h2&gt;

&lt;p&gt;Electron bundles Chromium and Node.js with your app. That makes it the easiest choice when a web team wants maximum desktop capability without introducing Rust or native UI frameworks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create electron-app@latest my-app &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vite-typescript
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A hardened Electron app usually has a main process, an isolated renderer, and a preload bridge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.ts — Node.js context&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BrowserWindow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ipcMain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shell&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;join&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BrowserWindow&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;mainWindow&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;BrowserWindow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;webPreferences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preload.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;contextIsolation&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="na"&gt;nodeIntegration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sandbox&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="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renderer/index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenReady&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createWindow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ipcMain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog:openFile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showOpenDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openFile&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filePaths&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="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;ipcMain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell:openExternal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openExternal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// preload.ts — narrow bridge between renderer and main&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contextBridge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ipcRenderer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;contextBridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exposeInMainWorld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;desktop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;openFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ipcRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog:openFile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;openExternal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ipcRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shell:openExternal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&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;Choose Electron when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a complex desktop product surface such as a code editor, design tool, database GUI, or communication app;&lt;/li&gt;
&lt;li&gt;consistent Chromium behavior on Windows, macOS, and Linux;&lt;/li&gt;
&lt;li&gt;Node.js libraries in the desktop backend;&lt;/li&gt;
&lt;li&gt;mature packaging, auto-update, crash reporting, and installer examples;&lt;/li&gt;
&lt;li&gt;a team that already knows Electron hardening patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid Electron when the app is a small utility where users will notice the installer size and memory baseline more than they notice Chromium consistency.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tauri: Choose Small Artifacts and Scoped Native Commands
&lt;/h2&gt;

&lt;p&gt;Tauri uses the operating system WebView for the frontend and Rust for native commands. That removes bundled Chromium from the app artifact, which is why Tauri apps usually ship much smaller than equivalent Electron apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create tauri-app@latest my-tauri-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-tauri-app
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run tauri dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Tauri app exposes native behavior as Rust commands instead of giving the renderer direct Node.js access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src-tauri/src/main.rs&lt;/span&gt;
&lt;span class="nd"&gt;#[tauri::command]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;read_project_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[cfg_attr(mobile,&lt;/span&gt; &lt;span class="nd"&gt;tauri::mobile_entry_point)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.invoke_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;generate_handler!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;read_project_file&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;generate_context!&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error while running tauri application"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontend TypeScript&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;invoke&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tauri-apps/api/core&lt;/span&gt;&lt;span class="dl"&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;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read_project_file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/Users/example/project/package.json&lt;/span&gt;&lt;span class="dl"&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;Choose Tauri when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a much smaller installer and a lower idle-memory baseline than Electron for similar UI complexity;&lt;/li&gt;
&lt;li&gt;Rust-backed commands for file, network, cryptography, or long-running local work;&lt;/li&gt;
&lt;li&gt;a permission model where native capabilities are deliberately exposed rather than globally available;&lt;/li&gt;
&lt;li&gt;signed update flows through Tauri's updater plugin;&lt;/li&gt;
&lt;li&gt;a team willing to test WebView differences across Windows, macOS, and Linux.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Tauri tradeoff is real: platform WebViews are not identical. Windows WebView2 is Chromium-based, macOS uses WebKit/WKWebView, and Linux WebView behavior depends on installed libraries. If your app uses advanced CSS or browser APIs, budget for cross-platform WebView QA.&lt;/p&gt;




&lt;h2&gt;
  
  
  Neutralino: Choose a Tiny Native Wrapper
&lt;/h2&gt;

&lt;p&gt;Neutralino wraps a web app in a native window and exposes a compact JavaScript API for OS, filesystem, storage, window, and process interactions. It does not try to be Electron with a smaller binary or Tauri without Rust; it is a smaller abstraction for smaller apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @neutralinojs/neu
neu create my-app &lt;span class="nt"&gt;--template&lt;/span&gt; neutralinojs/neutralinojs-minimal
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
neu run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minimal Neutralino config keeps the native surface explicit:&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;"applicationId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"com.example.utility"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defaultMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"window"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"documentRoot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/resources/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"enableNativeAPI"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokenSecurity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"one-time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nativeAllowList"&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="s2"&gt;"app.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"filesystem.readFile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"filesystem.writeFile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"storage.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"window.*"&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;"modes"&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;"window"&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;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resizable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;Choose Neutralino when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a tiny app wrapper for an internal tool, launcher, local dashboard, file converter, or tray utility;&lt;/li&gt;
&lt;li&gt;native window/storage/filesystem access without a full Node.js or Rust backend;&lt;/li&gt;
&lt;li&gt;simple distribution where manual or custom updates are acceptable;&lt;/li&gt;
&lt;li&gt;a small surface area and limited plugin needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid Neutralino when your app needs deep OS integration, complex background services, mature auto-update infrastructure, or a large ecosystem of desktop-specific packages.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bundle Size and Memory: Use Directional Ranges, Then Measure Your App
&lt;/h2&gt;

&lt;p&gt;Hello-world bundle and idle-memory numbers are useful only as a first filter. Electron is usually the largest because Chromium ships with the application. Tauri is usually much smaller because the OS provides the WebView. Neutralino is usually smallest for a simple wrapper.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric to test in your prototype&lt;/th&gt;
&lt;th&gt;Electron expectation&lt;/th&gt;
&lt;th&gt;Tauri expectation&lt;/th&gt;
&lt;th&gt;Neutralino expectation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Minimal installer/app artifact&lt;/td&gt;
&lt;td&gt;Largest&lt;/td&gt;
&lt;td&gt;Much smaller&lt;/td&gt;
&lt;td&gt;Smallest for simple apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle memory for simple shell&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rendering consistency&lt;/td&gt;
&lt;td&gt;Highest because Chromium is bundled&lt;/td&gt;
&lt;td&gt;Platform-dependent WebView behavior&lt;/td&gt;
&lt;td&gt;Platform-dependent WebView behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native backend weight&lt;/td&gt;
&lt;td&gt;Node.js process&lt;/td&gt;
&lt;td&gt;Rust binary&lt;/td&gt;
&lt;td&gt;Built-in API server plus optional extensions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/build prerequisites&lt;/td&gt;
&lt;td&gt;Node, native packaging dependencies&lt;/td&gt;
&lt;td&gt;Node plus Rust/Cargo and platform targets&lt;/td&gt;
&lt;td&gt;Node plus Neutralino CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the app is a developer tool with large data grids, terminals, plugins, and background services, the UI and workload can dominate the baseline. Build one vertical slice with the real shell, file access, tray behavior, updater, and a representative heavy screen before making the final call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security and Permission Model
&lt;/h2&gt;

&lt;p&gt;Electron security depends on disciplined configuration: &lt;code&gt;contextIsolation: true&lt;/code&gt;, &lt;code&gt;nodeIntegration: false&lt;/code&gt;, &lt;code&gt;sandbox: true&lt;/code&gt; where practical, strict Content Security Policy, narrow preload APIs, and careful IPC validation. Electron is secureable, but it gives teams enough power to create footguns.&lt;/p&gt;

&lt;p&gt;Tauri pushes teams toward a narrower native-command seam. The renderer calls explicit commands or plugin APIs; the Rust side validates inputs and owns native behavior. That model is a better default for many apps, but it still needs careful command design and plugin permission review.&lt;/p&gt;

&lt;p&gt;Neutralino reduces the surface by being smaller, then relies on token security and explicit native API allow-lists. That is attractive for utilities, but the smaller ecosystem means you own more custom integration work when the app grows beyond the core APIs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hidden costs matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hidden cost&lt;/th&gt;
&lt;th&gt;Electron&lt;/th&gt;
&lt;th&gt;Tauri&lt;/th&gt;
&lt;th&gt;Neutralino&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native plugin work&lt;/td&gt;
&lt;td&gt;Usually JavaScript/Node packages or native Node addons&lt;/td&gt;
&lt;td&gt;Rust commands/plugins; stronger seam but extra skill requirement&lt;/td&gt;
&lt;td&gt;Often custom extension or shell/native bridge work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Installer/signing/notarization&lt;/td&gt;
&lt;td&gt;Mature docs and ecosystem, still operationally heavy&lt;/td&gt;
&lt;td&gt;Official tooling plus Cargo/platform setup&lt;/td&gt;
&lt;td&gt;More custom process for production-grade distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web compatibility QA&lt;/td&gt;
&lt;td&gt;One Chromium baseline&lt;/td&gt;
&lt;td&gt;WebView2/WKWebView/WebKitGTK differences&lt;/td&gt;
&lt;td&gt;OS-WebView differences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-update hosting&lt;/td&gt;
&lt;td&gt;Common through Electron Forge/electron-builder/electron-updater&lt;/td&gt;
&lt;td&gt;Tauri updater plugin and signed payloads&lt;/td&gt;
&lt;td&gt;Usually custom/manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crash reporting/telemetry&lt;/td&gt;
&lt;td&gt;Many off-the-shelf examples&lt;/td&gt;
&lt;td&gt;Possible, but more app-specific&lt;/td&gt;
&lt;td&gt;Mostly custom&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Auto-Updates, Signing, and Release Operations
&lt;/h2&gt;

&lt;p&gt;The release pipeline often decides this comparison:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Electron:&lt;/strong&gt; mature packaging and update tooling through Electron Forge, electron-builder, and electron-updater. Good fit when your team wants a documented path for installers, GitHub Releases/S3 update feeds, and platform signing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tauri:&lt;/strong&gt; Cargo-based builds and Tauri's updater plugin. Good fit when signed update payloads and a Rust-native release pipeline are acceptable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neutralino:&lt;/strong&gt; no comparable batteries-included updater story. Good fit when manual updates, a custom version-check flow, or a controlled internal distribution channel is acceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before choosing, run a release rehearsal: build signed artifacts, install them on a clean VM, exercise first launch, trigger an update, and verify rollback behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which Should You Pick?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pick Electron if
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;the app is a complex desktop product with heavy UI and native integration needs;&lt;/li&gt;
&lt;li&gt;your team needs Chromium consistency more than tiny installers;&lt;/li&gt;
&lt;li&gt;Node.js libraries are core to local app behavior;&lt;/li&gt;
&lt;li&gt;mature packaging, updater, and community examples reduce delivery risk;&lt;/li&gt;
&lt;li&gt;you are building something closer to VS Code, Slack, Discord, Figma desktop, or a database GUI than a small utility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pick Tauri if
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;startup, memory, app size, and security posture are product requirements;&lt;/li&gt;
&lt;li&gt;you can own Rust commands and cross-platform WebView QA;&lt;/li&gt;
&lt;li&gt;the web frontend does not require exact Chromium behavior everywhere;&lt;/li&gt;
&lt;li&gt;you want a stricter seam between web UI and native capabilities;&lt;/li&gt;
&lt;li&gt;you are shipping a consumer productivity tool, local-first app, or internal desktop tool where resource usage matters.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pick Neutralino if
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;the app is a lightweight wrapper around an existing web UI;&lt;/li&gt;
&lt;li&gt;you need a tiny installer and a minimal native API surface;&lt;/li&gt;
&lt;li&gt;you can accept a smaller ecosystem and a custom/manual updater story;&lt;/li&gt;
&lt;li&gt;the product is a utility, kiosk shell, launcher, tray app, or internal helper.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Internal Links for Adjacent Decisions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For the broader desktop stack decision, use &lt;a href="https://www.pkgpulse.com/guides/best-desktop-app-frameworks-2026" rel="noopener noreferrer"&gt;Best Desktop App Frameworks 2026&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For the two-way incumbent/challenger comparison, use &lt;a href="https://www.pkgpulse.com/guides/electron-vs-tauri-2026" rel="noopener noreferrer"&gt;Electron vs Tauri 2026&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For adjacent cross-platform mobile choices, use &lt;a href="https://www.pkgpulse.com/guides/react-native-vs-expo-vs-capacitor-cross-platform-mobile-2026" rel="noopener noreferrer"&gt;React Native vs Expo vs Capacitor&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Compare package health for &lt;a href="https://www.pkgpulse.com/compare/electron-vs-tauri" rel="noopener noreferrer"&gt;Electron vs Tauri&lt;/a&gt; on PkgPulse.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Methodology and Sources
&lt;/h2&gt;

&lt;p&gt;This refresh checked official documentation and current package metadata on 2026-06-15 UTC. Package versions observed from npm during the refresh included &lt;code&gt;electron@42.4.0&lt;/code&gt;, &lt;code&gt;@tauri-apps/api@2.11.0&lt;/code&gt;, and &lt;code&gt;@neutralinojs/neu@11.7.2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sources consulted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tauri official docs: &lt;a href="https://tauri.app/start/" rel="noopener noreferrer"&gt;Tauri start guide&lt;/a&gt; and &lt;a href="https://v2.tauri.app/" rel="noopener noreferrer"&gt;Tauri v2 docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Electron official docs: &lt;a href="https://www.electronjs.org/docs/latest/" rel="noopener noreferrer"&gt;Electron documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Neutralino official docs: &lt;a href="https://neutralino.js.org/docs/" rel="noopener noreferrer"&gt;Neutralino documentation&lt;/a&gt; and &lt;a href="https://neutralino.js.org/docs/api/overview/" rel="noopener noreferrer"&gt;API overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm package metadata for Electron, Tauri CLI/API, Neutralino CLI/library, Electron Forge, and electron-builder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benchmark-style numbers in desktop-framework comparisons should be treated as directional until you measure your own app on your supported operating systems. The safest production process is to build a real vertical slice, sign it, install it on clean machines, measure startup/memory/artifact size, and test updates before committing to the runtime.&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/tauri-vs-electron-vs-neutralino-desktop-apps-javascript-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>desktop</category>
      <category>tauri</category>
      <category>electron</category>
      <category>javascript</category>
    </item>
    <item>
      <title>CS50 Review: Is It Worth It in 2026?</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 17 Jun 2026 16:00:41 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/cs50-review-is-it-worth-it-in-2026-k39</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/cs50-review-is-it-worth-it-in-2026-k39</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/cs50-review-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;CS50 — Harvard University's Introduction to Computer Science — is one of the most referenced courses in online education. Created by Professor David Malan, it has been running since 2007 and consistently ranks as the largest open online course at Harvard. Millions of learners have taken it.&lt;/p&gt;

&lt;p&gt;The core question for 2026: is CS50 still worth taking, who should take it, and what do you actually get out of it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Verdict
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes — for the right learner.&lt;/strong&gt; CS50 is the best free computer science foundations course available. It's genuinely rigorous, the problem sets are challenging, and completing it builds confidence and conceptual depth that many self-taught developers lack. It's NOT the fastest path to employment. It IS the best foundation-building course for people who want to truly understand how computers and code work before specializing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What CS50 Is
&lt;/h2&gt;

&lt;p&gt;CS50 is Harvard's on-campus introductory CS course, made available free online via edX and cs50.harvard.edu. The version you can take for free is identical to what Harvard undergraduates take — same lectures, same problem sets, same grading.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Full name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CS50's Introduction to Computer Science&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instructor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;David J. Malan (Harvard)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Platform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;cs50.harvard.edu (free) or edX (certificate costs $149)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;11 weeks (self-paced)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Weekly commitment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10–20 hours/week (varies by week)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Languages covered&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C, Python, SQL, HTML/CSS, JavaScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Certificate cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free to take, $149 for verified certificate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Student rating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.9/5 (edX)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What CS50 Covers
&lt;/h2&gt;

&lt;p&gt;CS50 covers more ground than most multi-month bootcamps — compressed into 11 weeks.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Scratch — computational thinking without syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;C — variables, loops, functions, memory concepts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;C — arrays, strings, cryptography&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Algorithms — search, sort, complexity (Big O notation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Memory — pointers, memory management, heap vs. stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Data Structures — linked lists, hash tables, trees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Python — transition from C, syntax, libraries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;SQL — databases, queries, schemas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;HTML, CSS, JavaScript — web basics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Flask — Python web framework, full-stack mini-project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Final Project — self-directed project of your choice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The progression is intentional:&lt;/strong&gt; CS50 starts in C deliberately. Working in a low-level language without memory management automatic handling builds intuition about what higher-level languages do for you. Python after C is a revelation.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Sets
&lt;/h2&gt;

&lt;p&gt;CS50's problem sets (psets) are where the real learning happens — and where the course's difficulty reputation comes from.&lt;/p&gt;

&lt;p&gt;Each week has a pset that requires implementing a real program: a Caesar cipher encryption tool, a credit card Luhn algorithm checker, a spell-checker with a hash table, a DNA strand matcher using Python.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes the psets hard:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They require genuine problem-solving, not copying a tutorial&lt;/li&gt;
&lt;li&gt;Some weeks (particularly Week 4 on memory and pointers) have a steep difficulty curve&lt;/li&gt;
&lt;li&gt;The automated grader (&lt;code&gt;check50&lt;/code&gt;) doesn't give partial credit for almost-right implementations&lt;/li&gt;
&lt;li&gt;There's no hand-holding — you're expected to figure out your approach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What makes them valuable:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completing a hard problem set produces a confidence and competence that easy exercises don't&lt;/li&gt;
&lt;li&gt;The implementations are real programs that do real things — not toy examples&lt;/li&gt;
&lt;li&gt;The variety across weeks (algorithms, databases, web) exposes you to multiple domains&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Honest time estimates per week:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy weeks (Python, SQL): 4–6 hours&lt;/li&gt;
&lt;li&gt;Hard weeks (Memory/pointers): 10–20 hours&lt;/li&gt;
&lt;li&gt;Most students report Week 4 (memory) as the biggest difficulty spike&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Certificate: Is $149 Worth It?
&lt;/h2&gt;

&lt;p&gt;You can complete CS50 entirely for free, including all lectures, problem sets, and the final project. The verified certificate ($149 from edX) adds Harvard's verification that you completed the course.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the $149 worth it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For most people: &lt;strong&gt;no, unless you're using it as a resume credential.&lt;/strong&gt; The learning value is identical free vs. paid. The certificate adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Official Harvard/edX verified credential you can add to LinkedIn&lt;/li&gt;
&lt;li&gt;A PDF certificate with your name and completion date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The employer recognition reality:&lt;/strong&gt; CS50 is widely recognized and respected — but primarily as a learning experience, not as a hiring credential. Saying "I completed CS50" in an interview signals genuine foundations. The certificate on your resume is secondary to the skills it built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If budget is a constraint:&lt;/strong&gt; Take it free. The learning outcome is unchanged.&lt;/p&gt;




&lt;h2&gt;
  
  
  CS50's Strength: Conceptual Depth
&lt;/h2&gt;

&lt;p&gt;What CS50 teaches that most practical programming courses don't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big O notation and algorithm complexity.&lt;/strong&gt; You'll understand why different sorting algorithms have different performance characteristics, and why this matters when writing code at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory management.&lt;/strong&gt; Week 4's deep dive into pointers and memory is mentally taxing — and produces developers who understand what's happening below the abstraction layers that Python and JavaScript hide from you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multiple language exposure.&lt;/strong&gt; Moving through C → Python → SQL → JavaScript in one course builds language-agnostic programming intuition. You understand that syntax is superficial; the underlying concepts transfer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem decomposition.&lt;/strong&gt; CS50's approach to each pset is explicitly about breaking problems into smaller pieces. This structured problem-solving approach is one of the most transferable professional skills in the course.&lt;/p&gt;




&lt;h2&gt;
  
  
  CS50's Limitations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Slow path to employability.&lt;/strong&gt; CS50 is not designed to get you a job. It's designed to give you foundational CS knowledge. If your goal is employment in 6 months, a Python bootcamp or the self-taught path via freeCodeCamp will get you there faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No frontend framework or React.&lt;/strong&gt; The web content covers HTML/CSS/JavaScript basics and Flask. Modern front-end development (React, Vue) and full-stack frameworks (Next.js, Django REST) are not covered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No data science or ML.&lt;/strong&gt; CS50 is a general introduction. For data science, follow up with CS50P (Python) or Andrew Ng's ML Specialization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pointers will frustrate you.&lt;/strong&gt; Week 4 causes a significant number of learners to quit. This isn't a flaw in the course — it's a real concept that matters — but it's a real attrition point.&lt;/p&gt;




&lt;h2&gt;
  
  
  The CS50 Family
&lt;/h2&gt;

&lt;p&gt;Beyond the original CS50, Harvard has published several follow-on courses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Course&lt;/th&gt;
&lt;th&gt;Topics&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CS50P&lt;/td&gt;
&lt;td&gt;Python Programming&lt;/td&gt;
&lt;td&gt;Python depth after CS50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CS50W&lt;/td&gt;
&lt;td&gt;Web Programming (Django, React)&lt;/td&gt;
&lt;td&gt;Full-stack web development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CS50AI&lt;/td&gt;
&lt;td&gt;Artificial Intelligence&lt;/td&gt;
&lt;td&gt;ML/AI fundamentals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CS50SQL&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;Database work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CS50x Cybersecurity&lt;/td&gt;
&lt;td&gt;Security basics&lt;/td&gt;
&lt;td&gt;Security introduction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All are free to take. CS50W in particular is a natural continuation for web developers — it covers Django and React in substantial depth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Should Take CS50
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Perfect for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-taught developers who feel shaky on fundamentals (what is memory? what's an algorithm? how do data structures work?)&lt;/li&gt;
&lt;li&gt;Career changers who have time for a rigorous foundation before specializing&lt;/li&gt;
&lt;li&gt;People who get frustrated when they don't understand &lt;em&gt;why&lt;/em&gt; things work, not just &lt;em&gt;how&lt;/em&gt; to do them&lt;/li&gt;
&lt;li&gt;Computer science students who want the best introductory curriculum available, free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not ideal for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People who need to be job-ready in 3–4 months — freeCodeCamp or a bootcamp is more direct&lt;/li&gt;
&lt;li&gt;Pure web developers who already have solid JavaScript and don't need low-level foundations&lt;/li&gt;
&lt;li&gt;Learners who find academic-style instruction frustrating&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  CS50 vs. Alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Duration&lt;/th&gt;
&lt;th&gt;Depth&lt;/th&gt;
&lt;th&gt;Job Focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CS50&lt;/td&gt;
&lt;td&gt;Free ($149 cert)&lt;/td&gt;
&lt;td&gt;11 weeks&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;freeCodeCamp&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;300+ hours&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Odin Project&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;6–9 months&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Angela Yu's Python (Udemy)&lt;/td&gt;
&lt;td&gt;~$15&lt;/td&gt;
&lt;td&gt;60+ hours&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bootcamp (in-person)&lt;/td&gt;
&lt;td&gt;$15,000+&lt;/td&gt;
&lt;td&gt;4–6 months&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;CS50 + freeCodeCamp&lt;/strong&gt; is a popular combination: CS50 builds the conceptual foundation, freeCodeCamp builds the practical skills and portfolio. Together, they produce a stronger developer than either alone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Rating
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Teaching quality&lt;/td&gt;
&lt;td&gt;5/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conceptual depth&lt;/td&gt;
&lt;td&gt;5/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Difficulty / rigor&lt;/td&gt;
&lt;td&gt;5/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job preparation&lt;/td&gt;
&lt;td&gt;2.5/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Certificate value&lt;/td&gt;
&lt;td&gt;3/5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Value for money&lt;/td&gt;
&lt;td&gt;5/5 (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overall&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.3/5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;CS50 is the best computer science foundations course available in 2026, and the fact that it's free makes it one of the most compelling learning investments you can make.&lt;/p&gt;

&lt;p&gt;It will not get you a job directly. It will make you a better developer, a stronger problem-solver, and someone who understands computing at a level that many practical-track learners don't.&lt;/p&gt;

&lt;p&gt;If you have 11 focused weeks and want to build genuine CS foundations: do CS50. If you need employment in 4 months: choose a more direct path and come back to CS50 later.&lt;/p&gt;

&lt;p&gt;See our &lt;a href="https://www.coursefacts.com/guides/self-taught-developer-guide-2026" rel="noopener noreferrer"&gt;self-taught developer guide&lt;/a&gt; for how CS50 fits in a full learning path, or our &lt;a href="https://www.coursefacts.com/guides/free-vs-paid-online-courses-2026" rel="noopener noreferrer"&gt;free vs paid online courses guide&lt;/a&gt; for context on when free resources like this are sufficient.&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.coursefacts.com/guides/cs50-review-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>programming</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Node 22 vs Node 24 in 2026: Current LTS Upgrade Guide</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 10 Jun 2026 16:01:00 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/node-22-vs-node-24-in-2026-current-lts-upgrade-guide-1oa5</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/node-22-vs-node-24-in-2026-current-lts-upgrade-guide-1oa5</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/nodejs-22-vs-nodejs-24-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are choosing between &lt;strong&gt;Node.js 22 and Node.js 24 in 2026&lt;/strong&gt;, use &lt;strong&gt;Node.js 24 for new production work&lt;/strong&gt;. It is the current active LTS line, has the longer support window, ships npm 11, includes a newer V8 engine, and now has stable built-in TypeScript type stripping in the maintained v24 line.&lt;/p&gt;

&lt;p&gt;Keep &lt;strong&gt;Node.js 22&lt;/strong&gt; when you already run production services on it and need a low-risk maintenance window. Node 22 is still an LTS release, but by May 2026 it is in maintenance and reaches end-of-life in April 2027. The upgrade is not an emergency, but teams should be testing Node 24 now instead of waiting until the final quarter before EOL.&lt;/p&gt;

&lt;p&gt;Source note: this refresh uses the Node.js release schedule, Node.js 22.0.0 and 24.0.0 release posts, the Node.js v24 TypeScript documentation, and the Node.js distribution index, checked May 15, 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: should you use Node 22 or Node 24?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New app, API, CLI, package, or Next.js service&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Use Node.js 24&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Current LTS, support through April 2028, npm 11, newer V8, stable type stripping in current v24 docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existing Node 22 production app&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Stay on 22 until tested, then schedule 24&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node 22 remains supported until April 2027, so you have time for dependency and CI validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native addons, legacy TLS, strict enterprise platform baselines&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Test 24 in parallel first&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;V8, npm, Undici/fetch, and bundled crypto dependencies can expose hidden compatibility issues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production runtime choice in May 2026&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Do not jump to Node 26 yet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node 26 is the Current line in May 2026 and does not become LTS until October 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package author support policy&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Test Node 22 and 24, default examples to 24&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node 22 still matters for consumers, but Node 24 is the current LTS baseline for new work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The short version: &lt;strong&gt;Node 24 is the right default; Node 22 is a supported maintenance runtime, not a greenfield choice.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Node.js LTS answer for May 2026
&lt;/h2&gt;

&lt;p&gt;The official release schedule shows this status in May 2026:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Release line&lt;/th&gt;
&lt;th&gt;Status in May 2026&lt;/th&gt;
&lt;th&gt;First release&lt;/th&gt;
&lt;th&gt;LTS start&lt;/th&gt;
&lt;th&gt;Maintenance start&lt;/th&gt;
&lt;th&gt;End of life&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 22, "Jod"&lt;/td&gt;
&lt;td&gt;Maintenance LTS&lt;/td&gt;
&lt;td&gt;2024-04-24&lt;/td&gt;
&lt;td&gt;2024-10-29&lt;/td&gt;
&lt;td&gt;2025-10-21&lt;/td&gt;
&lt;td&gt;2027-04-30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 24, "Krypton"&lt;/td&gt;
&lt;td&gt;Active LTS&lt;/td&gt;
&lt;td&gt;2025-05-06&lt;/td&gt;
&lt;td&gt;2025-10-28&lt;/td&gt;
&lt;td&gt;2026-10-20&lt;/td&gt;
&lt;td&gt;2028-04-30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js 26&lt;/td&gt;
&lt;td&gt;Current, not LTS yet&lt;/td&gt;
&lt;td&gt;2026-05-05&lt;/td&gt;
&lt;td&gt;2026-10-28&lt;/td&gt;
&lt;td&gt;2027-10-20&lt;/td&gt;
&lt;td&gt;2029-04-30&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That means searchers asking "current Node.js LTS" or "Node 22 vs 24" need a practical answer, not just a release calendar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Current LTS for new projects:&lt;/strong&gt; Node.js 24.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Still-supported older LTS:&lt;/strong&gt; Node.js 22.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current non-LTS line:&lt;/strong&gt; Node.js 26, useful for experimentation and early compatibility testing, not conservative production adoption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrade urgency:&lt;/strong&gt; plan and test now; finish production migration from 22 before April 2027.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For historical context, the older &lt;a href="https://www.pkgpulse.com/guides/nodejs-22-vs-nodejs-20-upgrade-guide" rel="noopener noreferrer"&gt;Node.js 22 vs Node.js 20 upgrade guide&lt;/a&gt; explains why teams moved to 22. This page is the canonical current-LTS decision guide for &lt;strong&gt;Node 22 vs Node 24&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed from Node 22 to Node 24?
&lt;/h2&gt;

&lt;p&gt;Node 24 is not a risky rewrite of the runtime. It is the next LTS baseline with newer bundled dependencies, a longer support window, and several developer-experience improvements that matter in CI and tooling.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. npm 11 replaces npm 10
&lt;/h3&gt;

&lt;p&gt;Node 24 ships npm 11. The Node.js 24 release notes describe npm 11 as bringing performance, security, and compatibility improvements. In practice, the upgrade affects teams in three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install and resolution behavior can differ from npm 10;&lt;/li&gt;
&lt;li&gt;package-lock changes should be committed deliberately, not mixed into unrelated feature work;&lt;/li&gt;
&lt;li&gt;workspace and peer-dependency edge cases should be tested in CI before the production runtime flips.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use a separate lockfile PR when possible:&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="c"&gt;# test the runtime first&lt;/span&gt;
nvm &lt;span class="nb"&gt;install &lt;/span&gt;24
nvm use 24
npm ci
npm &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# then regenerate intentionally if your project commits package-lock.json&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;package-lock.json
npm &lt;span class="nb"&gt;install
&lt;/span&gt;git add package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your production repo uses Bun, pnpm, or Yarn instead of npm, npm 11 is less important operationally. You still inherit Node 24's runtime and V8 changes, but the lockfile story belongs to your actual package manager.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. V8 moves from the Node 22 line's 12.x series to Node 24's 13.6 line
&lt;/h3&gt;

&lt;p&gt;The Node.js 24.0.0 release post calls out V8 13.6 and new JavaScript capabilities including &lt;code&gt;Float16Array&lt;/code&gt;, explicit resource management, &lt;code&gt;RegExp.escape()&lt;/code&gt;, WebAssembly Memory64, and &lt;code&gt;Error.isError()&lt;/code&gt;.&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="c1"&gt;// Node 24: RegExp.escape() is available through the newer V8 line&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react+dom (legacy)&lt;/span&gt;&lt;span class="dl"&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;safe&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react+dom (legacy)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For most web services, this is a compatibility and platform-modernization reason rather than a promise of universal throughput gains. CPU-heavy workloads may benefit from newer V8 optimizations, but you should benchmark your own app instead of relying on generic runtime numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Built-in TypeScript type stripping is now stable in the maintained v24 docs
&lt;/h3&gt;

&lt;p&gt;Node 22 introduced the path toward built-in TypeScript support, but it was experimental in the 22 line. The Node.js v24 TypeScript documentation now marks type stripping as stable, with history entries noting that type stripping was enabled by default in v23.6.0, warnings were removed in v24.3.0, and the feature became stable in v24.12.0.&lt;/p&gt;

&lt;p&gt;That makes Node 24 much more pleasant for scripts and internal tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/seed.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkgpulse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Refreshing data for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node scripts/seed.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;type stripping&lt;/strong&gt;, not full TypeScript compilation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it does not type-check your program;&lt;/li&gt;
&lt;li&gt;decorators and syntax requiring transforms still need explicit transform support or a third-party runner;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tsconfig&lt;/code&gt; path aliases and production bundling still need your normal build tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For backend apps, keep &lt;code&gt;tsc --noEmit&lt;/code&gt; in CI. Use native type stripping for scripts, CLIs, small services, and local developer ergonomics.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. URLPattern and newer Web-platform APIs are available globally
&lt;/h3&gt;

&lt;p&gt;Node 24 also promotes more Web-platform compatibility. The 24.0.0 release notes call out &lt;code&gt;URLPattern&lt;/code&gt; as globally available and Undici 7 as the bundled HTTP client foundation.&lt;/p&gt;

&lt;p&gt;That matters if your app shares routing, URL, or fetch-related utilities between browser and server code:&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;apiRoute&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;URLPattern&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/packages/:name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/api/packages/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. &lt;code&gt;require(esm)&lt;/code&gt; keeps improving
&lt;/h3&gt;

&lt;p&gt;Node 22 was the big release for &lt;code&gt;require()&lt;/code&gt; loading synchronous ESM graphs. In the current v24 line, &lt;code&gt;require(esm)&lt;/code&gt; is stable. That lowers the pain of consuming ESM-only packages from older CommonJS code.&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="c1"&gt;// Node 22+ started making this practical; current Node 24 makes it a safer baseline.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execa&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;execa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not use this as an excuse to avoid ESM forever. Use it as a migration bridge: remove async &lt;code&gt;import()&lt;/code&gt; wrappers where they were only workarounds, but keep package-level module decisions explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is different about Node 22 in 2026?
&lt;/h2&gt;

&lt;p&gt;Node 22 is still a good runtime. It introduced important features that made the Node ecosystem easier to maintain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;built-in WebSocket client support;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;require(esm)&lt;/code&gt; compatibility improvements;&lt;/li&gt;
&lt;li&gt;stream high-water-mark changes that improved common I/O throughput;&lt;/li&gt;
&lt;li&gt;the early path for native TypeScript type stripping;&lt;/li&gt;
&lt;li&gt;a stable LTS base that many hosting providers and enterprise platforms adopted quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue is not that Node 22 is bad. The issue is that it is now the older LTS line. It is in maintenance, and its EOL date is closer than many teams' upgrade calendars.&lt;/p&gt;

&lt;p&gt;Use Node 22 when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your production baseline is already on 22 and stable;&lt;/li&gt;
&lt;li&gt;your hosting provider, appliance, or enterprise runtime policy has not approved 24 yet;&lt;/li&gt;
&lt;li&gt;native addons need rebuild/testing against Node 24's V8/module ABI;&lt;/li&gt;
&lt;li&gt;you need to avoid package-lock churn during a release freeze.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not start a new 2026 project on Node 22 unless you have a platform constraint that forces it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node 22 vs Node 24 comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Node.js 22&lt;/th&gt;
&lt;th&gt;Node.js 24&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LTS status in May 2026&lt;/td&gt;
&lt;td&gt;Maintenance LTS&lt;/td&gt;
&lt;td&gt;Active LTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codename&lt;/td&gt;
&lt;td&gt;Jod&lt;/td&gt;
&lt;td&gt;Krypton&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LTS start&lt;/td&gt;
&lt;td&gt;2024-10-29&lt;/td&gt;
&lt;td&gt;2025-10-28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance start&lt;/td&gt;
&lt;td&gt;2025-10-21&lt;/td&gt;
&lt;td&gt;2026-10-20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End of life&lt;/td&gt;
&lt;td&gt;2027-04-30&lt;/td&gt;
&lt;td&gt;2028-04-30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm line&lt;/td&gt;
&lt;td&gt;npm 10.x in current v22 builds&lt;/td&gt;
&lt;td&gt;npm 11.x in current v24 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V8 line&lt;/td&gt;
&lt;td&gt;12.x in current v22 builds&lt;/td&gt;
&lt;td&gt;13.6.x in current v24 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript type stripping&lt;/td&gt;
&lt;td&gt;Experimental path in the 22 line&lt;/td&gt;
&lt;td&gt;Stable in current v24 docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;RegExp.escape()&lt;/code&gt; / &lt;code&gt;Float16Array&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Not the baseline reason to choose 22&lt;/td&gt;
&lt;td&gt;Available through the newer V8 line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;require(esm)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Introduced/usable&lt;/td&gt;
&lt;td&gt;Stable in current v24 line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production default for new work&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best use in 2026&lt;/td&gt;
&lt;td&gt;Existing apps with controlled upgrade windows&lt;/td&gt;
&lt;td&gt;New apps and planned upgrades&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Upgrade risk checklist for Node 22 to Node 24
&lt;/h2&gt;

&lt;p&gt;A good Node 24 migration is mostly validation, not rewriting. Work through these checks before changing production runtime images.&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtime and deployment baseline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;.nvmrc&lt;/code&gt;, &lt;code&gt;.node-version&lt;/code&gt;, Volta, Docker images, CI runtime settings, and managed-hosting runtime settings in one reviewable change.&lt;/li&gt;
&lt;li&gt;Run the same test suite on Node 22 and 24 before removing Node 22 from the matrix.&lt;/li&gt;
&lt;li&gt;Keep rollback images or deployment settings for Node 22 until Node 24 has run under real traffic.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;22&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;24&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Native addons and package engines
&lt;/h3&gt;

&lt;p&gt;Native modules and packages with strict &lt;code&gt;engines&lt;/code&gt; fields are the most common upgrade blockers.&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="c"&gt;# find direct dependencies with native build hooks&lt;/span&gt;
npm &lt;span class="nb"&gt;ls &lt;/span&gt;node-gyp node-pre-gyp prebuild-install &lt;span class="nt"&gt;--all&lt;/span&gt;

&lt;span class="c"&gt;# surface engines mismatches before deployment&lt;/span&gt;
npx check-node-version &lt;span class="nt"&gt;--node&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;=24"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a dependency rejects Node 24 through an old &lt;code&gt;engines&lt;/code&gt; range, check whether a newer package version supports it before loosening constraints locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  npm and lockfile behavior
&lt;/h3&gt;

&lt;p&gt;If your project uses npm, Node 24 means npm 11. Keep this separate from application logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run &lt;code&gt;npm ci&lt;/code&gt; first to test existing lockfiles;&lt;/li&gt;
&lt;li&gt;regenerate &lt;code&gt;package-lock.json&lt;/code&gt; only when necessary;&lt;/li&gt;
&lt;li&gt;review workspace and peer-dependency changes carefully;&lt;/li&gt;
&lt;li&gt;do not mix a lockfile migration with unrelated feature work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fetch, Undici, and URL handling
&lt;/h3&gt;

&lt;p&gt;Node 24 bundles a newer Undici line and continues tightening the server-side Fetch implementation. Audit code that relies on non-standard fetch options, custom agents, proxy behavior, or unusual URL parsing.&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="c1"&gt;// Keep fetch options boring and spec-aligned.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://registry.npmjs.org/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&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;Also check older URL parsing assumptions. Prefer &lt;code&gt;URL.canParse()&lt;/code&gt; or explicit null/error handling instead of assuming every invalid URL path throws in the same way across versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenSSL and TLS compatibility
&lt;/h3&gt;

&lt;p&gt;The Node distribution index shows current Node 22 and current Node 24 patch releases both carry modern OpenSSL 3.5.x builds by mid-May 2026. Treat crypto/TLS as a compatibility surface for &lt;strong&gt;current patch-line upgrades&lt;/strong&gt;, not only the major-version jump to 24.&lt;/p&gt;

&lt;p&gt;Audit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;legacy certificates and private keys;&lt;/li&gt;
&lt;li&gt;old partner APIs that only support weak ciphers or old TLS versions;&lt;/li&gt;
&lt;li&gt;tests that mock low-level crypto behavior;&lt;/li&gt;
&lt;li&gt;Docker images that pin an older system CA bundle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your app talks only to modern HTTPS services, this is usually uneventful. If it integrates with old enterprise appliances, payment gateways, or internal PKI, test the handshake in staging before flipping production.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript runtime scripts
&lt;/h3&gt;

&lt;p&gt;Node 24's type stripping is useful for internal scripts, but it should not replace type checking:&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="c"&gt;# Good: execute a simple script directly&lt;/span&gt;
node scripts/refresh-package-metadata.ts

&lt;span class="c"&gt;# Still required: type-check the project&lt;/span&gt;
tsc &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avoid changing production TypeScript build strategy during the Node runtime upgrade unless that is the explicit goal of the PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which version should different teams choose?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New product teams
&lt;/h3&gt;

&lt;p&gt;Choose &lt;strong&gt;Node.js 24&lt;/strong&gt;. It gives you the current LTS line, support through April 2028, and a cleaner developer experience for TypeScript scripts and modern JavaScript APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Existing Node 22 services
&lt;/h3&gt;

&lt;p&gt;Stay on &lt;strong&gt;Node.js 22&lt;/strong&gt; until the upgrade checklist passes, then move to 24. The right schedule is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;add Node 24 to CI;&lt;/li&gt;
&lt;li&gt;fix package/native-addon failures;&lt;/li&gt;
&lt;li&gt;test staging or a preview deployment;&lt;/li&gt;
&lt;li&gt;regenerate npm lockfiles only if needed;&lt;/li&gt;
&lt;li&gt;move low-risk services first;&lt;/li&gt;
&lt;li&gt;remove Node 22 from the matrix after production is stable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Package authors
&lt;/h3&gt;

&lt;p&gt;Test both Node 22 and 24 while Node 22 remains supported. If you are raising your minimum supported version in 2026, make the support policy explicit in &lt;code&gt;package.json&lt;/code&gt; and release notes.&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;"engines"&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;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=22"&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;For packages that rely on v24-only features, use &lt;code&gt;&amp;gt;=24&lt;/code&gt; and explain why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform and DevOps teams
&lt;/h3&gt;

&lt;p&gt;Standardize new runtime images on &lt;strong&gt;Node 24&lt;/strong&gt;, but keep Node 22 images available for rollback until the last service migrates. Update base image scans, SBOM generation, and runtime policy docs at the same time so developers do not have conflicting guidance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# old baseline&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:22-alpine&lt;/span&gt;

&lt;span class="c"&gt;# new LTS baseline&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:24-alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What not to overstate
&lt;/h2&gt;

&lt;p&gt;Avoid three common mistakes in Node 22 vs 24 planning:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Do not claim Node 22 is unsupported.&lt;/strong&gt; It is supported until April 2027, but it is no longer the best default for new work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not promise universal performance gains.&lt;/strong&gt; Node 24 has a newer V8 and npm 11, but app-level throughput depends on workload, dependencies, and deployment shape.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not treat Node 26 as the LTS answer in May 2026.&lt;/strong&gt; It is the Current line until October 2026.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Frequently searched questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the current Node.js LTS version in 2026?
&lt;/h3&gt;

&lt;p&gt;Node.js 24 is the current active LTS line in May 2026. Node.js 22 is still a supported maintenance LTS line, and Node.js 26 is the Current non-LTS line until October 2026.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use Node 22 or Node 24?
&lt;/h3&gt;

&lt;p&gt;Use Node 24 for new projects. Keep Node 22 for existing production apps until you have tested dependencies, native addons, fetch/Undici behavior, TLS integrations, and CI images against Node 24.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Node 22 still safe for production?
&lt;/h3&gt;

&lt;p&gt;Yes. Node 22 remains supported through April 2027. The risk is not immediate security abandonment; the risk is letting the upgrade slip until the EOL window is too close.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Node 24 a breaking upgrade?
&lt;/h3&gt;

&lt;p&gt;For most applications, no. The likely issues are package-manager lockfile changes, native addon rebuilds, strict dependency engine ranges, HTTP/fetch edge cases, and legacy crypto/TLS integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should package authors drop Node 22 support?
&lt;/h3&gt;

&lt;p&gt;Not automatically. Node 22 is still within its support window. If your package can test both Node 22 and 24 cheaply, keep both until your users have had enough migration time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final verdict
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Node.js 24 is the current LTS default for 2026.&lt;/strong&gt; It has the longer support window, newer bundled tooling, newer V8, and stable TypeScript type stripping in the current v24 documentation. Use it for new projects and make it the target for planned upgrades.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js 22 is a supported maintenance runtime, not a failure state.&lt;/strong&gt; Existing production apps can stay on 22 while you validate the migration, but teams should have a Node 24 upgrade plan well before April 2027.&lt;/p&gt;

&lt;p&gt;For broader runtime context, see &lt;a href="https://www.pkgpulse.com/guides/best-javascript-runtimes-2026" rel="noopener noreferrer"&gt;best JavaScript runtimes 2026&lt;/a&gt;. For dependency and package-ecosystem signals during an upgrade, see &lt;a href="https://www.pkgpulse.com/guides/20-fastest-growing-npm-packages-2026" rel="noopener noreferrer"&gt;20 fastest growing npm packages 2026&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Compare Node.js-related npm packages on &lt;a href="https://pkgpulse.com" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Compare Node.js 22 and Node.js 24 package health on &lt;a href="https://www.pkgpulse.com/compare/nodejs-22-vs-nodejs-24" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://www.pkgpulse.com/guides/best-javascript-testing-frameworks-2026" rel="noopener noreferrer"&gt;Best JavaScript Testing Frameworks 2026&lt;/a&gt;, &lt;a href="https://www.pkgpulse.com/guides/best-websocket-libraries-nodejs-2026" rel="noopener noreferrer"&gt;Best WebSocket Libraries Node.js 2026&lt;/a&gt;, &lt;a href="https://www.pkgpulse.com/guides/best-monorepo-tools-2026" rel="noopener noreferrer"&gt;Best Monorepo Tools 2026&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pkgpulse.com/guides/nodejs-22-vs-nodejs-20-upgrade-guide" rel="noopener noreferrer"&gt;Node.js 20 to 22 upgrade checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pkgpulse.com/guides/bun-vs-vite-2026" rel="noopener noreferrer"&gt;Bun vs Vite frontend build tradeoffs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pkgpulse.com/guides/20-fastest-growing-npm-packages-2026" rel="noopener noreferrer"&gt;Node.js package ecosystem trends&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/nodejs-22-vs-nodejs-24-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Boot.dev vs Zero to Mastery 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 10 Jun 2026 16:00:54 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/bootdev-vs-zero-to-mastery-2026-3ebo</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/bootdev-vs-zero-to-mastery-2026-3ebo</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/boot-dev-vs-zero-to-mastery-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;. This is a syndicated repost with the canonical URL set to the original guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Boot.dev and Zero to Mastery are both subscription-based learning platforms aimed at people who want to become developers. Both market themselves to career-changers and complete beginners. Both have active communities and explicit job-readiness content. That's roughly where the similarities end.&lt;/p&gt;

&lt;p&gt;Boot.dev is an opinionated, linear, backend-specific platform with gamified coding exercises that force you to write code to advance. Zero to Mastery is a broad, video-first catalog covering 50+ stacks and technologies, with an enormous community and explicit career guidance woven throughout the curriculum.&lt;/p&gt;

&lt;p&gt;Choosing between them is a question of what you want from your learning: focused depth with active practice, or wide coverage with comprehensive career support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Verdict
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choose Boot.dev&lt;/strong&gt; if you're committed to a backend engineering career, want to be forced to write real code at every step, and benefit from gamified structure that keeps you consistent over months. The linear path from Python fundamentals to deploying Go applications is the most coherent beginner-to-backend curriculum currently available on any paid platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Zero to Mastery&lt;/strong&gt; if you want breadth — to explore multiple technologies and stacks before committing to a specialization, or if you need explicit career guidance (resume, LinkedIn, interview prep) integrated into your learning from day one. ZTM's community and career infrastructure are genuine differentiators.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Boot.dev&lt;/th&gt;
&lt;th&gt;Zero to Mastery&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monthly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$29/month&lt;/td&gt;
&lt;td&gt;$39/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Annual&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$192/year ($16/month)&lt;/td&gt;
&lt;td&gt;$228/year ($19/month)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lifetime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not offered&lt;/td&gt;
&lt;td&gt;$999 one-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Free tier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;First chapters of each course&lt;/td&gt;
&lt;td&gt;No free access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trial&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Free first chapters&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Boot.dev is the cheaper option at both monthly and annual tiers. The $192/year vs $228/year difference isn't dramatic ($36/year), but Boot.dev's free tier is a meaningful advantage — you can work through the first few lessons of any course before committing to a subscription.&lt;/p&gt;

&lt;p&gt;Zero to Mastery charges $39/month without an annual discount that meaningfully reduces the monthly rate. At $228/year, ZTM works out to $19/month all year — there's no financial incentive to commit annually versus paying monthly and canceling when you're between active learning periods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One practical consideration:&lt;/strong&gt; ZTM's catalog is broad enough that most learners actively use it for longer continuous periods. Boot.dev's linear path may have natural completion milestones after which you might pause the subscription and return later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Boot.dev on price and free trial generosity.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Learning Approach: The Fundamental Difference
&lt;/h2&gt;

&lt;p&gt;This is where Boot.dev and ZTM diverge most significantly — and understanding the difference is more important than comparing any other feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boot.dev: Active Coding Required
&lt;/h3&gt;

&lt;p&gt;Boot.dev's entire product is built around a single conviction: &lt;strong&gt;you cannot learn to code by watching videos.&lt;/strong&gt; Every lesson introduces a concept and then requires you to write passing code in the browser-based editor before advancing.&lt;/p&gt;

&lt;p&gt;There's no option to skip the exercises. There's no way to mark a lesson complete without submitting working code. If your code fails the automated tests, you stay on that lesson until it passes.&lt;/p&gt;

&lt;p&gt;This sounds obvious, but it is radically different from how most platforms work. On Udemy, you can "complete" a 40-hour React course without ever opening a code editor. On ZTM, the video format means the only active engagement is pausing to code alongside the instructor — which requires discipline that many learners don't maintain.&lt;/p&gt;

&lt;p&gt;Boot.dev eliminates the discipline question. The platform structure provides it for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the in-browser coding environment does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every lesson has a browser-based editor pre-configured for the lesson's language (Python, Go, JavaScript, SQL, Bash)&lt;/li&gt;
&lt;li&gt;Click "Run" — your code executes against the lesson's test suite&lt;/li&gt;
&lt;li&gt;Clear output shows which tests pass and fail&lt;/li&gt;
&lt;li&gt;No local environment setup required to start learning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For beginners, this last point is not trivial. Environment setup — installing Python, configuring VS Code, understanding PATH variables — is a real friction point that causes learners to quit before writing a single meaningful line of code. Boot.dev removes this barrier completely for the first months of learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero to Mastery: Video-First, Applied Supplementary
&lt;/h3&gt;

&lt;p&gt;ZTM is a traditional video course platform. Instructors (primarily Andrei Neagoie and a curated group of co-instructors) deliver content in recorded video lectures. You pause, you code alongside, you complete the projects built during the course.&lt;/p&gt;

&lt;p&gt;The ZTM courses are genuinely well-produced, and Neagoie in particular is an excellent beginner-to-intermediate educator who builds concepts carefully. But the format places the responsibility for active engagement on the learner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What ZTM does to encourage active practice:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding challenges and exercises within courses&lt;/li&gt;
&lt;li&gt;Portfolio-building projects at the end of course sections&lt;/li&gt;
&lt;li&gt;Community study groups and accountability partners via Discord&lt;/li&gt;
&lt;li&gt;Regular live Q&amp;amp;A sessions with instructors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are meaningful supports, but they're supplementary to video consumption rather than gate-keeping it. You can watch all the ZTM videos without writing a single line and the platform won't stop you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest outcome data:&lt;/strong&gt; Self-reported completion rates for video-based courses are low across the industry — 10–15% on most platforms. Boot.dev doesn't publish course completion rates, but its exercise-gated format makes passive non-engagement structurally harder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner for active learners: Boot.dev. Winner for visual/video learners: ZTM.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Curriculum Structure and Coverage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Boot.dev: One Linear Backend Path
&lt;/h3&gt;

&lt;p&gt;Boot.dev has a single intended learning path. This is a feature, not a limitation.&lt;/p&gt;

&lt;p&gt;The path is sequenced so that every course builds on the last. You cannot productively skip to "Build an HTTP Server in Go" if you haven't completed the Go fundamentals course, because the exercises assume you know the language. The linear structure removes the anxiety of curriculum choice — you always know what to do next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Boot.dev Backend Path (2026):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Foundations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn Python — variables, functions, loops, OOP basics&lt;/li&gt;
&lt;li&gt;Learn JavaScript — Node.js focus, async, modules&lt;/li&gt;
&lt;li&gt;Learn Functional Programming — using Python (map/filter/reduce, immutability)&lt;/li&gt;
&lt;li&gt;Learn Object-Oriented Programming — using Python (classes, inheritance, interfaces)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — Computer Science&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn Algorithms — Big O, sorting, searching, hash maps&lt;/li&gt;
&lt;li&gt;Learn Data Structures — linked lists, trees, graphs, heaps&lt;/li&gt;
&lt;li&gt;Learn Memory Management — pointers, heap vs stack (uses C for hands-on understanding)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 3 — Backend Engineering&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn Go — syntax, interfaces, goroutines, channels (the platform flagship)&lt;/li&gt;
&lt;li&gt;Build an HTTP Server in Go — implement HTTP/1.1 from scratch&lt;/li&gt;
&lt;li&gt;Learn Web Servers in Go — REST APIs, middleware, error handling&lt;/li&gt;
&lt;li&gt;Learn SQL — SELECT, JOINs, aggregates, transactions (PostgreSQL)&lt;/li&gt;
&lt;li&gt;Learn Database Design — normalization, indexing, query optimization&lt;/li&gt;
&lt;li&gt;Learn Docker — containerization, Docker Compose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 4 — Advanced&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn Cryptography — hashing, encryption, JWT&lt;/li&gt;
&lt;li&gt;Build a Blog Aggregator — multi-service Go app with PostgreSQL backend&lt;/li&gt;
&lt;li&gt;Learn CI/CD — GitHub Actions, automated testing, deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Estimated duration:&lt;/strong&gt; Boot.dev estimates 12–18 months of 1–2 hours/day to complete the full path. This is realistic and honest — it's a serious curriculum commitment, not a "learn to code in 3 months" pitch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Boot.dev doesn't cover:&lt;/strong&gt; The path skips frontend development entirely. There is no HTML, CSS, or React course. If your goal is full-stack web development, you'll need to supplement Boot.dev with frontend resources. This is an intentional product decision — Boot.dev is explicitly a backend specialization platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero to Mastery: Multiple Tracks, 100+ Courses
&lt;/h3&gt;

&lt;p&gt;ZTM's catalog is organized around distinct learning tracks rather than a single linear path:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main ZTM Tracks:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Track&lt;/th&gt;
&lt;th&gt;Key Courses&lt;/th&gt;
&lt;th&gt;Languages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complete Web Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTML, CSS, JS, React, Node, PostgreSQL&lt;/td&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complete Python Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python core, Django, ML intro&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Science &amp;amp; ML&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pandas, NumPy, TensorFlow, Keras&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DevOps &amp;amp; Cloud&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Docker, Kubernetes, AWS&lt;/td&gt;
&lt;td&gt;Bash, YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blockchain/Web3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ethereum, Solidity&lt;/td&gt;
&lt;td&gt;Solidity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Computer Science&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DS&amp;amp;A, system design, interview prep&lt;/td&gt;
&lt;td&gt;Language-agnostic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Career&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Resume, LinkedIn, salary negotiation&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 breadth is genuine and impressive. A ZTM subscriber can go from "I want to learn to code" to exploring Python data science, then pivot to web development, then take the DevOps track — all within one subscription. For learners who haven't yet decided what kind of developer they want to be, this flexibility has real value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The limitation of breadth:&lt;/strong&gt; ZTM's catalog covers a lot of surface area but doesn't always match Boot.dev's depth within a specific domain. The Go coverage on ZTM, for example, is limited compared to Boot.dev's flagship Go curriculum. The cryptography and HTTP fundamentals content simply doesn't exist at ZTM at the level Boot.dev provides.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Gamification Question
&lt;/h2&gt;

&lt;p&gt;Boot.dev's RPG-style gamification is either a major selling point or a minor annoyance depending on who you ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Boot.dev gamifies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XP (experience points) earned for completing lessons and exercises&lt;/li&gt;
&lt;li&gt;Character levels tied to accumulated XP&lt;/li&gt;
&lt;li&gt;Achievements and badges for streaks, perfect submissions, course completions&lt;/li&gt;
&lt;li&gt;A global leaderboard&lt;/li&gt;
&lt;li&gt;Daily challenges for bonus XP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For learners who are motivated by streaks and visible progress, this works well. Boot.dev's own retention data (published on their blog) shows that learners who maintain a daily streak complete significantly more of the curriculum. The gamification keeps the habit loop active during the periods when raw motivation fades.&lt;/p&gt;

&lt;p&gt;For learners who find RPG metaphors condescending or distracting, the gamification is purely cosmetic — it doesn't prevent you from learning, but it adds visual noise you might not want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ZTM has no gamification.&lt;/strong&gt; Progress tracking is basic video completion percentages. There are no points, no achievements, no streaks. The accountability structure ZTM offers is community-based (Discord study groups, accountability partners) rather than platform-driven.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Boot.dev for learners motivated by gamification. ZTM for learners who find gamification distracting.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Community and Support
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Boot.dev Community
&lt;/h3&gt;

&lt;p&gt;Boot.dev's community is primarily the official Discord server. It's active, technically focused, and notable for instructor participation — Lane Wagner (Boot.dev's founder and primary instructor) is genuinely present in the Discord. Questions about course content, Go best practices, and career questions get answered by someone who writes the courses, not just a community manager.&lt;/p&gt;

&lt;p&gt;The Discord has dedicated channels by course/language, a jobs channel, and a showcase channel for completed projects. For an educational platform, the community-to-product integration is tighter than average.&lt;/p&gt;

&lt;p&gt;Boot.dev also maintains a YouTube channel and blog with supplementary content on Go, backend development, and programming career topics — useful as extensions of the platform even for non-subscribers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero to Mastery Community
&lt;/h3&gt;

&lt;p&gt;ZTM's community is one of its strongest assets. The Discord has 500,000+ members across channels covering every ZTM course and many adjacent topics. The scale creates something Boot.dev can't match at its size: at any hour of the day, there are people at every stage of the curriculum available to help.&lt;/p&gt;

&lt;p&gt;ZTM runs structured community features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Study groups&lt;/strong&gt; organized by course or technology&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accountability groups&lt;/strong&gt; (cohorts that commit to learning goals together)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly live Q&amp;amp;A sessions&lt;/strong&gt; with Andrei Neagoie&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job hunting channels&lt;/strong&gt; with resume feedback and job posting sharing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alumni network&lt;/strong&gt; for networking post-completion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The community size is a double-edged sword. In a 500K-member Discord, signal-to-noise can be a challenge. Boot.dev's smaller, more focused community tends to have higher-quality technical discussion per message, while ZTM's community is better for finding people at your exact learning stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: ZTM for community scale and career support. Boot.dev for instructor-accessible technical discussion.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Job-Readiness and Career Support
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Boot.dev's Approach to Job Prep
&lt;/h3&gt;

&lt;p&gt;Boot.dev's career support is curriculum-embedded rather than explicitly structured. The argument: if you complete the full backend path, you will have the skills for a backend role. The portfolio is the curriculum itself — the HTTP server you built, the blog aggregator you deployed, the Go services you implemented.&lt;/p&gt;

&lt;p&gt;Boot.dev provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A public learner profile with completed courses listed (shareable as a portfolio)&lt;/li&gt;
&lt;li&gt;GitHub integration (projects built during the curriculum are real repositories)&lt;/li&gt;
&lt;li&gt;Resume/LinkedIn guidance articles on the blog&lt;/li&gt;
&lt;li&gt;Career discussion channels in the Discord&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What Boot.dev lacks: a formal hiring partner network, direct recruiter connections, or structured interview prep curriculum. The platform is focused on skill acquisition and trusts learners to handle job applications with the skills they've built.&lt;/p&gt;

&lt;h3&gt;
  
  
  ZTM's Approach to Job Prep
&lt;/h3&gt;

&lt;p&gt;ZTM is explicit about career outcomes from the start. The platform's tagline is "Zero to Mastery" — going from no skills to employable. Career support includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated "Career of the Future" course&lt;/strong&gt; (resume writing, LinkedIn, job applications, salary negotiation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical interview preparation&lt;/strong&gt; — a full course on data structures, algorithms, and system design for interview contexts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resume review&lt;/strong&gt; in Discord by community members and occasionally instructors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mock interview practice&lt;/strong&gt; in the Discord&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job posting sharing&lt;/strong&gt; in the community channels&lt;/li&gt;
&lt;li&gt;Career guidance integrated into flagship courses (each major course has sections on "what jobs use these skills")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Andrei Neagoie specifically designs courses with job outcomes in mind. He has been open about his own experience transitioning into tech and structures curriculum to address the specific gaps that interviewers test for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: ZTM for explicit career support infrastructure. Boot.dev for portfolio-ready project work.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Instructor Profile
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lane Wagner (Boot.dev)
&lt;/h3&gt;

&lt;p&gt;Lane Wagner founded Boot.dev and is the primary instructor for most of the Go curriculum — the platform's most important content. He's a working Go developer who used Go in production before building Boot.dev, and the courses reflect this: the Go content is opinionated in the way that only someone who has debugged goroutine leaks at 2am is opinionated.&lt;/p&gt;

&lt;p&gt;The one-instructor-led platform means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent teaching style and philosophy throughout the curriculum&lt;/li&gt;
&lt;li&gt;Direct access to the person who wrote the course when something is confusing&lt;/li&gt;
&lt;li&gt;A coherent progression logic — courses connect because one person designed the whole path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The risk: if Lane Wagner's teaching style doesn't work for you, there's limited recourse. The catalog doesn't have diverse instructor voices for most topics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Andrei Neagoie (Zero to Mastery)
&lt;/h3&gt;

&lt;p&gt;Andrei Neagoie's flagship courses (Complete Web Developer, Complete Python Developer) are ZTM's main draw. He transitioned into software development mid-career and specifically designs courses to be accessible to learners coming from non-technical backgrounds.&lt;/p&gt;

&lt;p&gt;ZTM has expanded to include additional instructors (Yihua Zhang on React/GraphQL, Andrei Dumitrescu on Python/DevOps, Mo Binni on data science), which expands catalog breadth but introduces inconsistency. Neagoie's courses are better than the platform average; some other instructors are strong, some are uneven.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Boot.dev for curriculum coherence. ZTM for diversity of instructors and learner accessibility.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Each Platform Is For
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Boot.dev Is the Right Choice If
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You're specifically targeting a &lt;strong&gt;backend engineering role&lt;/strong&gt; — your goal is clear and you don't want to cover frontend ground&lt;/li&gt;
&lt;li&gt;You learn best by &lt;strong&gt;doing&lt;/strong&gt; — the exercise-gated format will keep you engaged in ways video courses won't&lt;/li&gt;
&lt;li&gt;You want to learn &lt;strong&gt;Go&lt;/strong&gt; — Boot.dev's Go curriculum is the most thorough structured Go learning path available&lt;/li&gt;
&lt;li&gt;You benefit from &lt;strong&gt;gamification&lt;/strong&gt; — streaks, XP, and leaderboards motivate you&lt;/li&gt;
&lt;li&gt;You want a &lt;strong&gt;linear path without decision fatigue&lt;/strong&gt; — one curriculum, one order, no choosing&lt;/li&gt;
&lt;li&gt;You're a complete beginner who wants to &lt;strong&gt;skip environment setup friction&lt;/strong&gt; — the browser-based coding environment removes the first week of headaches&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Zero to Mastery Is the Right Choice If
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You're &lt;strong&gt;undecided on specialization&lt;/strong&gt; — ZTM's broad catalog lets you explore Python, JavaScript, data science, and DevOps before committing&lt;/li&gt;
&lt;li&gt;You're targeting a &lt;strong&gt;full-stack or web development role&lt;/strong&gt; — ZTM's Complete Web Developer track is more comprehensive than anything Boot.dev offers for the frontend&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;structured career guidance&lt;/strong&gt; — resume, LinkedIn, interview prep, salary negotiation&lt;/li&gt;
&lt;li&gt;You want a &lt;strong&gt;large community&lt;/strong&gt; — 500K members means help is always available and networking is possible&lt;/li&gt;
&lt;li&gt;You're a &lt;strong&gt;visual learner&lt;/strong&gt; — the video format with production quality instruction suits how you learn&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;Python for data science&lt;/strong&gt; — ZTM's Python and ML curriculum exceeds Boot.dev's data science coverage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Head-to-Head Scorecard
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Boot.dev&lt;/th&gt;
&lt;th&gt;Zero to Mastery&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monthly price&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$29/month&lt;/td&gt;
&lt;td&gt;$39/month&lt;/td&gt;
&lt;td&gt;Boot.dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Annual price&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$192/year&lt;/td&gt;
&lt;td&gt;$228/year&lt;/td&gt;
&lt;td&gt;Boot.dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Free tier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ First chapters&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Boot.dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active coding required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Every lesson&lt;/td&gt;
&lt;td&gt;❌ Video-first&lt;/td&gt;
&lt;td&gt;Boot.dev (for active learners)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gamification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full RPG system&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Boot.dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backend depth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Exceptional (Go/Python)&lt;/td&gt;
&lt;td&gt;✅ Good&lt;/td&gt;
&lt;td&gt;Boot.dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frontend coverage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;td&gt;✅ Comprehensive&lt;/td&gt;
&lt;td&gt;ZTM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Course breadth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Backend only&lt;/td&gt;
&lt;td&gt;✅ 50+ stacks&lt;/td&gt;
&lt;td&gt;ZTM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Community size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Smaller, focused&lt;/td&gt;
&lt;td&gt;500K+ members&lt;/td&gt;
&lt;td&gt;ZTM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Career support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Minimal explicit&lt;/td&gt;
&lt;td&gt;✅ Full suite&lt;/td&gt;
&lt;td&gt;ZTM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python/Data Science&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Backend Python&lt;/td&gt;
&lt;td&gt;✅ Data Science Python&lt;/td&gt;
&lt;td&gt;ZTM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instructor access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Lane in Discord&lt;/td&gt;
&lt;td&gt;✅ Monthly Q&amp;amp;A&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Curriculum coherence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Single linear path&lt;/td&gt;
&lt;td&gt;❌ Multiple tracks&lt;/td&gt;
&lt;td&gt;Boot.dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Beginners welcome&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ (no env setup)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Tie&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Boot.dev is the better platform for learners who have decided: "I want to be a backend developer."&lt;/strong&gt; Its linear path, exercise-gated progression, and Go curriculum are uniquely well-designed for that specific goal. If you're looking at job descriptions for backend engineering roles and you want the most structured active-learning path to get there, Boot.dev is the answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero to Mastery is the better platform for learners who are still figuring out their direction&lt;/strong&gt; — or who have decided on full-stack or web development rather than pure backend. The Complete Web Developer course is a strong end-to-end full-stack curriculum, the community is enormous, and the career support infrastructure is the most explicit of any developer education platform at this price point.&lt;/p&gt;

&lt;p&gt;The platforms are genuinely complementary for one specific learner type: if you want to do a ZTM Complete Web Developer course first (to get full-stack context and job-readiness skills), then continue with Boot.dev to go deeper on backend fundamentals, that's a legitimate and powerful combination. Use ZTM to understand what backend developers do and how they fit into a full application; use Boot.dev to actually become one.&lt;/p&gt;

&lt;p&gt;At $29–$39/month, neither platform is a significant financial commitment. The real investment is time. &lt;strong&gt;Pick the one whose format matches how you actually learn&lt;/strong&gt;, not just how you wish you learned — a Boot.dev subscription you use daily at $29/month will advance your career more than a ZTM subscription you watch passively.&lt;/p&gt;




&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sources: Boot.dev official course catalog and pricing (March 2026), Zero to Mastery official catalog and pricing (March 2026), Reddit r/learnprogramming comparison threads, Boot.dev Discord public channels, ZTM Discord community, Lane Wagner's YouTube channel (public curriculum previews), Andrei Neagoie's Udemy course metrics, Course Report platform reviews, Boot.dev and ZTM blog posts on learner outcomes&lt;/li&gt;
&lt;li&gt;Data as of: March 2026&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Already decided on Boot.dev? See &lt;a href="https://www.coursefacts.com/guides/boot-dev-review-2026" rel="noopener noreferrer"&gt;Boot.dev Review 2026&lt;/a&gt; for a standalone deep dive on the platform.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Looking at Zero to Mastery specifically? See &lt;a href="https://www.coursefacts.com/guides/zero-to-mastery-review-2026" rel="noopener noreferrer"&gt;Zero to Mastery Review 2026&lt;/a&gt; for a detailed evaluation of the platform's strengths and weaknesses.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.coursefacts.com/guides/boot-dev-vs-zero-to-mastery-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>career</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
