<?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>TanStack Router vs React Router Framework Mode Guide</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 28 Oct 2026 16:00:19 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/tanstack-router-vs-react-router-framework-mode-guide-4jn5</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/tanstack-router-vs-react-router-framework-mode-guide-4jn5</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/tanstack-router-vs-react-router-framework-mode-guide-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's note: This URL is kept for readers arriving from older links. The primary, indexable guide is &lt;a href="https://www.pkgpulse.com/guides/tanstack-router-vs-react-router-framework-mode-2026" rel="noopener noreferrer"&gt;TanStack Router vs React Router Framework Mode 2026&lt;/a&gt;. This page is set to noindex so search visibility consolidates on the main guide.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Compare TanStack Router vs React Router Framework Mode Guide 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 TanStack Router vs React Router Framework Mode Guide
&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;TanStack Router&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;React Router Framework Mode&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 TanStack Router vs React Router Framework Mode Guide 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/tanstack-router-vs-react-router-framework-mode-guide-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Andrew Ng ML Specialization vs fast.ai 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 28 Oct 2026 16:00:10 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/andrew-ng-ml-specialization-vs-fastai-2026-57jb</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/andrew-ng-ml-specialization-vs-fastai-2026-57jb</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/andrew-ng-ml-specialization-vs-fast-ai-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;Andrew Ng's Machine Learning Specialization and fast.ai Practical Deep Learning for Coders both still deserve short-list status in 2026, but they solve different learning problems. &lt;strong&gt;Andrew Ng is the safer first machine-learning course for most beginners. fast.ai is the stronger practical deep-learning course for people who can already code and want to build models quickly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The wrong choice is rarely about quality. It is about sequence. If you need a structured path through supervised learning, neural networks, decision trees, unsupervised learning, recommender systems, and core ML vocabulary, start with Andrew Ng. If you already have Python fluency and want practical PyTorch/deep-learning projects immediately, start with fast.ai.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source check: Coursera, DeepLearning.AI, fast.ai course pages, and fast.ai public materials were checked on May 22, 2026. Public pages can change pricing, pacing estimates, and enrollment labels without notice, so verify current details before paying.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick recommendation
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Learner profile&lt;/th&gt;
&lt;th&gt;Better first choice&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 to ML, some basic Python&lt;/td&gt;
&lt;td&gt;Andrew Ng Machine Learning Specialization&lt;/td&gt;
&lt;td&gt;More structured, beginner-friendly, and broad across classical ML plus neural networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comfortable Python developer who wants projects fast&lt;/td&gt;
&lt;td&gt;fast.ai Practical Deep Learning&lt;/td&gt;
&lt;td&gt;You build working models immediately and learn theory around the work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wants Coursera certificate or employer reimbursement&lt;/td&gt;
&lt;td&gt;Andrew Ng&lt;/td&gt;
&lt;td&gt;Coursera provides the clearer certificate path when you pay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wants a free practical course&lt;/td&gt;
&lt;td&gt;fast.ai&lt;/td&gt;
&lt;td&gt;The course and book materials are free online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wants PyTorch and modern deep-learning workflow&lt;/td&gt;
&lt;td&gt;fast.ai&lt;/td&gt;
&lt;td&gt;The course uses PyTorch, fastai, notebooks, Hugging Face-adjacent workflows, and deployment examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wants the strongest long-term path&lt;/td&gt;
&lt;td&gt;Andrew Ng first, then fast.ai&lt;/td&gt;
&lt;td&gt;Foundations first, practical deep-learning fluency second&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The core difference: map vs workshop
&lt;/h2&gt;

&lt;p&gt;Andrew Ng gives you the map. fast.ai gives you the workshop.&lt;/p&gt;

&lt;p&gt;Andrew Ng's specialization is bottom-up. You learn regression, classification, cost functions, gradient descent, overfitting, regularization, neural networks, decision trees, unsupervised learning, recommenders, and reinforcement-learning basics in a controlled sequence.&lt;/p&gt;

&lt;p&gt;fast.ai is top-down. You start building useful deep-learning models early, then work backward into the internals. That makes it motivating for developers who learn by doing, but more ambiguous for learners who need a clean conceptual map before they touch powerful tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Andrew Ng Machine Learning Specialization
&lt;/h2&gt;

&lt;p&gt;Andrew Ng's current Machine Learning Specialization is offered by Stanford and DeepLearning.AI on &lt;a href="https://www.coursefacts.com/platform/coursera" rel="noopener noreferrer"&gt;Coursera&lt;/a&gt;. It is organized as three courses and uses Python-era tools such as NumPy, scikit-learn, TensorFlow, and Jupyter-style labs.&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;Current read&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Provider&lt;/td&gt;
&lt;td&gt;Stanford + DeepLearning.AI on Coursera&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Level&lt;/td&gt;
&lt;td&gt;Beginner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Format&lt;/td&gt;
&lt;td&gt;Three-course specialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tools&lt;/td&gt;
&lt;td&gt;Python, NumPy, scikit-learn, TensorFlow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;ML foundations, structured learning, certificate-oriented learners&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weakness&lt;/td&gt;
&lt;td&gt;Not enough open-ended project depth by itself&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The specialization's durable strength is diagnosis. It helps learners understand why a model is underfitting, overfitting, failing to generalize, or choosing a bad decision boundary. That vocabulary still matters when you later work with deep learning, LLMs, RAG, or AI evaluation.&lt;/p&gt;

&lt;p&gt;Read the full &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 module-by-module breakdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  fast.ai Practical Deep Learning for Coders
&lt;/h2&gt;

&lt;p&gt;fast.ai Practical Deep Learning for Coders is a free, top-down course from Jeremy Howard and the fast.ai team. It is designed for people with some coding experience who want to apply deep learning and machine learning to practical problems.&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;Current read&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Provider&lt;/td&gt;
&lt;td&gt;fast.ai&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Level&lt;/td&gt;
&lt;td&gt;Practical developer course, not programming-from-zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Format&lt;/td&gt;
&lt;td&gt;Free self-paced videos, notebooks, and book materials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tools&lt;/td&gt;
&lt;td&gt;Python, PyTorch, fastai, notebooks, deployment examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Practical deep learning, projects, applied model work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weakness&lt;/td&gt;
&lt;td&gt;Can feel magical or nonlinear if you lack foundations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;fast.ai is often more exciting early because you train models quickly. The risk is that learners can build before they understand. That is not always bad. For many developers, seeing a working model creates the motivation to backfill theory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Andrew Ng prerequisites
&lt;/h3&gt;

&lt;p&gt;Andrew Ng is more forgiving for learners who know basic Python but are new to ML. You should be comfortable with variables, functions, loops, simple algebra, graphs, and notebook exercises. You do not need to be a professional software engineer before starting.&lt;/p&gt;

&lt;h3&gt;
  
  
  fast.ai prerequisites
&lt;/h3&gt;

&lt;p&gt;fast.ai says the course is for people with some coding experience. In practice, you will have a much better time if you are already comfortable with Python, notebooks, imports, package installs, file paths, and debugging stack traces. The course moves quickly because it wants you building from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will build and understand
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;Andrew Ng&lt;/th&gt;
&lt;th&gt;fast.ai&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Classical ML vocabulary&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;td&gt;Some, but less central&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deep-learning projects&lt;/td&gt;
&lt;td&gt;Introductory&lt;/td&gt;
&lt;td&gt;Stronger and earlier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mathematical intuition&lt;/td&gt;
&lt;td&gt;Stronger&lt;/td&gt;
&lt;td&gt;Added around practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python ML workflow&lt;/td&gt;
&lt;td&gt;Good foundation&lt;/td&gt;
&lt;td&gt;More practical and notebook-heavy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portfolio artifacts&lt;/td&gt;
&lt;td&gt;Needs extra projects&lt;/td&gt;
&lt;td&gt;More immediate project momentum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production MLOps&lt;/td&gt;
&lt;td&gt;Not the focus&lt;/td&gt;
&lt;td&gt;Not complete; still needs follow-up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither course is a full job path. For ML roles, you still need projects, statistics depth, data work, deployment, monitoring, and interview preparation.&lt;/p&gt;

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

&lt;p&gt;fast.ai has the simpler pricing story: the course and book materials are free online. You may still pay indirectly for compute if you choose paid notebooks or cloud GPUs, but the course itself is freely available.&lt;/p&gt;

&lt;p&gt;Andrew Ng's specialization uses Coursera's platform model. Public pages show enrollment/free-start language and a paid certificate/subscription path. The exact cost can vary by country, promotion, trial state, and Coursera plan. If your employer reimburses Coursera certificates, Andrew Ng has the clearer credential story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which should you take first?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  If you are a beginner
&lt;/h3&gt;

&lt;p&gt;Start with Andrew Ng. It gives you structure, language, and conceptual confidence. Afterward, take fast.ai when you want to build visible deep-learning projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you are already a strong Python developer
&lt;/h3&gt;

&lt;p&gt;You can start with fast.ai if you learn best by building. Keep Andrew Ng nearby as the conceptual backfill when loss functions, regularization, train/test splits, or model evaluation become fuzzy.&lt;/p&gt;

&lt;h3&gt;
  
  
  If your goal is AI engineering or LLM apps
&lt;/h3&gt;

&lt;p&gt;Neither course is enough by itself. Andrew Ng gives useful ML foundations, and fast.ai gives practical model-building momentum, but LLM APIs, RAG, agents, and evals require a separate AI-engineering path. Use &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; and &lt;a href="https://www.coursefacts.com/guides/best-ai-engineering-courses-developers-2026" rel="noopener noreferrer"&gt;best AI engineering courses for developers&lt;/a&gt; after the foundation layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  If your goal is a certificate
&lt;/h3&gt;

&lt;p&gt;Choose Andrew Ng. Coursera's certificate path is easier to explain to an employer or reimbursement system than a free self-paced course.&lt;/p&gt;

&lt;h3&gt;
  
  
  If your goal is strongest long-term learning
&lt;/h3&gt;

&lt;p&gt;Do both. Andrew Ng gives the map. fast.ai gives the workshop. The sequence is stronger than treating them as interchangeable substitutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common sequencing mistake
&lt;/h2&gt;

&lt;p&gt;The common mistake is starting with fast.ai because it looks more modern, then quitting because the top-down pace feels chaotic. The opposite mistake is finishing Andrew Ng and assuming you are now job-ready without building original projects.&lt;/p&gt;

&lt;p&gt;A better sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Andrew Ng for foundations.&lt;/li&gt;
&lt;li&gt;fast.ai for practical deep-learning projects.&lt;/li&gt;
&lt;li&gt;One original project with real data.&lt;/li&gt;
&lt;li&gt;AI engineering, MLOps, or domain specialization depending on your career goal.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Andrew Ng vs fast.ai is not a contest between good and bad courses. It is a sequencing decision.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Andrew Ng Machine Learning Specialization&lt;/strong&gt; if you want the most reliable first ML course: structured, beginner-friendly, broad, and conceptually durable.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;fast.ai Practical Deep Learning for Coders&lt;/strong&gt; if you are already comfortable with code and want to build practical deep-learning models quickly with modern tools.&lt;/p&gt;

&lt;p&gt;If you are unsure, start with Andrew Ng. If you already know you learn best by building, start with fast.ai. If you are serious about ML, plan to use both for different jobs.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Coursera, &lt;a href="https://www.coursera.org/specializations/machine-learning-introduction" rel="noopener noreferrer"&gt;Machine Learning Specialization&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;li&gt;DeepLearning.AI, &lt;a href="https://www.deeplearning.ai/specializations/machine-learning/" rel="noopener noreferrer"&gt;Machine Learning Specialization&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;li&gt;fast.ai, &lt;a href="https://course.fast.ai/" rel="noopener noreferrer"&gt;Practical Deep Learning for Coders&lt;/a&gt;, accessed May 22, 2026.&lt;/li&gt;
&lt;li&gt;fast.ai, &lt;a href="https://github.com/fastai/fastbook" rel="noopener noreferrer"&gt;fastbook repository&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/andrew-ng-ml-specialization-vs-fast-ai-2026" rel="noopener noreferrer"&gt;CourseFacts&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>FlashList vs FlatList vs LegendList 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 21 Oct 2026 16:01:07 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/flashlist-vs-flatlist-vs-legendlist-2026-4pem</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/flashlist-vs-flatlist-vs-legendlist-2026-4pem</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/flashlist-vs-flatlist-vs-legendlist-react-native-lists-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;h1&gt;
  
  
  FlashList vs FlatList vs LegendList: React Native Lists 2026
&lt;/h1&gt;

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

&lt;p&gt;Rendering long lists in React Native is famously challenging — FlatList is the built-in solution but struggles with scroll jank and blank flashes for large datasets. &lt;strong&gt;FlatList&lt;/strong&gt; (built into React Native) works for lists under a few hundred items but degrades significantly beyond that. &lt;strong&gt;FlashList&lt;/strong&gt; (Shopify) is the production-tested replacement — uses a recycler pattern that reuses rendered components instead of destroying and recreating them, achieving 5-10x better performance for large datasets. &lt;strong&gt;LegendList&lt;/strong&gt; is the newest entry — built on React Native's Fabric architecture and Reanimated, claiming to fix blank flashes and providing even smoother scrolling for very large lists. For most apps (&amp;lt; 500 items): FlatList. For production apps with large datasets (500+ items): FlashList. For apps hitting FlashList's limits or needing the smoothest possible experience: LegendList.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FlatList blanks at high scroll speed&lt;/strong&gt; — unmounted items render as blank white space&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FlashList reuses DOM components&lt;/strong&gt; — no creation/destruction overhead; 5-10x faster than FlatList&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LegendList is built on Fabric/JSI&lt;/strong&gt; — new architecture only, but eliminates blank flashes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FlashList requires &lt;code&gt;estimatedItemSize&lt;/code&gt;&lt;/strong&gt; — must set an estimated item height/width&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FlatList is zero setup&lt;/strong&gt; — built into React Native, works for most use cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FlashList GitHub stars: 4k&lt;/strong&gt; — Shopify uses it in their production apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All three support horizontal lists&lt;/strong&gt; — &lt;code&gt;horizontal&lt;/code&gt; prop works across all&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why FlatList Struggles at Scale
&lt;/h2&gt;

&lt;p&gt;React Native's FlatList uses a windowing approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List with 10,000 items:
  - Renders ~20 items in the visible viewport
  - Destroys components as they scroll off-screen
  - Creates new components as they scroll into view

Problem: Creation/destruction is expensive
  - JS creates new component instances
  - Bridge sends layout data to native
  - At high scroll speed: blank flash while new items render
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FlashList's recycler approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FlashList recycler:
  - Keeps ~30 component instances in memory
  - When item scrolls off: recycle it for the next incoming item
  - Update props instead of recreating component
  - No blank flashes — always showing content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  FlatList: The Built-In Standard
&lt;/h2&gt;

&lt;p&gt;FlatList is React Native's built-in virtualized list. Zero setup, well-documented, and sufficient for most use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Usage
&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;FlatList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&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&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&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="nl"&gt;author&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;publishedAt&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;function&lt;/span&gt; &lt;span class="nf"&gt;PostItem&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="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&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="o"&gt;&amp;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="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostsList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostItem&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&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="nx"&gt;item&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="c1"&gt;// Performance optimizations&lt;/span&gt;
      &lt;span class="nx"&gt;removeClippedSubviews&lt;/span&gt;&lt;span class="o"&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="c1"&gt;// Unmount off-screen views&lt;/span&gt;
      &lt;span class="nx"&gt;maxToRenderPerBatch&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;// Batch render 10 at a time&lt;/span&gt;
      &lt;span class="nx"&gt;windowSize&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;// Render 10 * viewport height&lt;/span&gt;
      &lt;span class="nx"&gt;initialNumToRender&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;// First render: 15 items&lt;/span&gt;
      &lt;span class="nx"&gt;getItemLayout&lt;/span&gt;&lt;span class="o"&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="nx"&gt;index&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;// Fixed height optimization&lt;/span&gt;
        &lt;span class="na"&gt;length&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;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;
  
  
  FlatList Optimization Tips
&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;// 1. Memoize renderItem to prevent unnecessary re-renders&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostItem&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&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;// 2. Memoize PostItem component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PostItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;memo&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="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&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;item&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&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;// 3. Use getItemLayout for fixed-height items (much faster)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getItemLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="nx"&gt;Post&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="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;length&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="c1"&gt;// Fixed item height&lt;/span&gt;
    &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;index&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;// 4. Use keyExtractor returning stable IDs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyExtractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="nx"&gt;Post&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;item&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;OptimizedList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;getItemLayout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getItemLayout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;removeClippedSubviews&lt;/span&gt;&lt;span class="o"&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="nx"&gt;maxToRenderPerBatch&lt;/span&gt;&lt;span class="o"&gt;=&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="nx"&gt;windowSize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;
  
  
  Pull-to-Refresh and Infinite Scroll
&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;function&lt;/span&gt; &lt;span class="nf"&gt;InfinitePostsList&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;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPosts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;refreshing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRefreshing&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadMore&lt;/span&gt; &lt;span class="o"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&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="nf"&gt;setLoading&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;newPosts&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;fetchPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&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="nf"&gt;setPosts&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&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;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newPosts&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nf"&gt;setPage&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&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;p&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="nf"&gt;setLoading&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refresh&lt;/span&gt; &lt;span class="o"&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="nf"&gt;setRefreshing&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;freshPosts&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;fetchPosts&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="nf"&gt;setPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;freshPosts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setPage&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="nf"&gt;setRefreshing&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;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostItem&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&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="nx"&gt;item&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;onEndReached&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loadMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onEndReachedThreshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;refreshing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refreshing&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onRefresh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;ListFooterComponent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ActivityIndicator&lt;/span&gt; &lt;span class="o"&gt;/&amp;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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;
  
  
  FlashList: Production-Grade Performance
&lt;/h2&gt;

&lt;p&gt;FlashList from Shopify uses a recycler algorithm that achieves near-native scroll performance for large lists.&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;npx expo &lt;span class="nb"&gt;install&lt;/span&gt; @shopify/flash-list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic Usage (Drop-in for FlatList)
&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;FlashList&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;@shopify/flash-list&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;PostsList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlashList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostItem&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&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="nx"&gt;item&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;estimatedItemSize&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;// Required — FlashList uses this for layout estimation&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;
  
  
  FlashList with Variable Height Items
&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;// FlashList handles variable-height items well&lt;/span&gt;
&lt;span class="c1"&gt;// Just provide estimatedItemSize as average height&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MessagesList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlashList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&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="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MessageItem&lt;/span&gt;
          &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&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="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="o"&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="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="o"&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="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="nx"&gt;estimatedItemSize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;// Average message height&lt;/span&gt;
      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&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="nx"&gt;item&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;inverted&lt;/span&gt;  &lt;span class="c1"&gt;// Show newest messages at bottom (chat-style)&lt;/span&gt;
      &lt;span class="nx"&gt;onEndReached&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loadOlderMessages&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onEndReachedThreshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;
  
  
  FlashList Performance Tuning
&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;// Advanced FlashList configuration for maximum performance&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;OptimizedFlashList&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;data&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlashList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&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="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ItemComponent&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="nx"&gt;estimatedItemSize&lt;/span&gt;&lt;span class="o"&gt;=&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;// Override recycling type per item (for mixed layouts)&lt;/span&gt;
      &lt;span class="nx"&gt;getItemType&lt;/span&gt;&lt;span class="o"&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="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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&lt;/span&gt;&lt;span class="dl"&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&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;// Pre-render invisible items for smoother scrolling&lt;/span&gt;
      &lt;span class="nx"&gt;drawDistance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;// Pixels above/below viewport to pre-render&lt;/span&gt;

      &lt;span class="c1"&gt;// Override estimated list size for better initial scroll&lt;/span&gt;
      &lt;span class="nx"&gt;estimatedListSize&lt;/span&gt;&lt;span class="o"&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="mi"&gt;2000&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;400&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

      &lt;span class="c1"&gt;// Diagnostic: shows which items are recycled vs new&lt;/span&gt;
      &lt;span class="c1"&gt;// (development only)&lt;/span&gt;
      &lt;span class="c1"&gt;// disableAutoLayout={false}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&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;
  
  
  Migrating from FlatList to FlashList
&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;// Before (FlatList)&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;FlatList&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&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&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="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;removeClippedSubviews&lt;/span&gt;&lt;span class="o"&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="nx"&gt;maxToRenderPerBatch&lt;/span&gt;&lt;span class="o"&gt;=&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// After (FlashList) — add estimatedItemSize, remove FlatList-specific props&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;FlashList&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;@shopify/flash-list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlashList&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&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="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;estimatedItemSize&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;// Add this&lt;/span&gt;
  &lt;span class="c1"&gt;// Remove: removeClippedSubviews, maxToRenderPerBatch — FlashList handles these internally&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  LegendList: New Architecture Performance
&lt;/h2&gt;

&lt;p&gt;LegendList is built for React Native's new architecture (Fabric + JSI). It aims to eliminate blank flashes entirely through synchronized rendering.&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; @legendapp/list
&lt;span class="c"&gt;# Requires React Native New Architecture (Fabric)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic Usage
&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;LegendList&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;@legendapp/list&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;PostsList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LegendList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PostItem&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&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="nx"&gt;item&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;estimatedItemSize&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;// LegendList-specific: recycles with Reanimated for buttery smooth scrolling&lt;/span&gt;
      &lt;span class="nx"&gt;recycleItems&lt;/span&gt;
    &lt;span class="o"&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;
  
  
  LegendList with Dynamic Heights
&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;// LegendList handles dynamic heights better than FlashList&lt;/span&gt;
&lt;span class="c1"&gt;// No need to specify item type for mixed layouts&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DynamicList&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FeedItem&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LegendList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&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;renderItem&lt;/span&gt;&lt;span class="o"&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="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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ImageCard&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextCard&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DefaultCard&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;      &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="nx"&gt;estimatedItemSize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;recycleItems&lt;/span&gt;
      &lt;span class="nx"&gt;maintainScrollAtEnd&lt;/span&gt;  &lt;span class="c1"&gt;// Keeps scroll position when new items added at bottom&lt;/span&gt;
    &lt;span class="o"&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;
  
  
  Performance Benchmark
&lt;/h2&gt;

&lt;p&gt;Based on community benchmarks (scrolling 10,000 item list at maximum speed):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;FlatList&lt;/th&gt;
&lt;th&gt;FlashList&lt;/th&gt;
&lt;th&gt;LegendList&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blank flashes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frequent&lt;/td&gt;
&lt;td&gt;Rare&lt;/td&gt;
&lt;td&gt;None*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Initial render time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;60fps scroll&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often drops&lt;/td&gt;
&lt;td&gt;Mostly yes&lt;/td&gt;
&lt;td&gt;Yes (Fabric)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Large dataset (10k)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;✅ Fast&lt;/td&gt;
&lt;td&gt;✅ Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup effort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;estimatedItemSize&lt;/td&gt;
&lt;td&gt;Fabric required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mixed item types&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getItemType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*LegendList requires New Architecture (Fabric)&lt;/p&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;FlatList&lt;/th&gt;
&lt;th&gt;FlashList&lt;/th&gt;
&lt;th&gt;LegendList&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in&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;New Architecture required&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;Recycler pattern&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;Variable heights&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;estimatedItemSize&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Horizontal&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;SectionList equiv&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SectionList&lt;/td&gt;
&lt;td&gt;✅ sections&lt;/td&gt;
&lt;td&gt;In progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pull-to-refresh&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;GitHub stars&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;4.4k&lt;/td&gt;
&lt;td&gt;1.5k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Production usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Universal&lt;/td&gt;
&lt;td&gt;✅ Shopify&lt;/td&gt;
&lt;td&gt;Growing&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;Choose FlatList if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your list has under 200-300 items and performance is acceptable&lt;/li&gt;
&lt;li&gt;You need zero additional dependencies&lt;/li&gt;
&lt;li&gt;You're working with SectionList (grouped items) — use React Native's SectionList&lt;/li&gt;
&lt;li&gt;Compatibility with older React Native versions matters&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Your list has 500+ items or performance is visibly poor with FlatList&lt;/li&gt;
&lt;li&gt;You're on the old React Native architecture (not yet on Fabric)&lt;/li&gt;
&lt;li&gt;You're building a production app (Shopify uses this at scale)&lt;/li&gt;
&lt;li&gt;You need a reliable drop-in FlatList replacement with minimal API changes&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;You're already on React Native's New Architecture (Fabric/Nitro)&lt;/li&gt;
&lt;li&gt;Blank flashes are unacceptable (media feeds, photo galleries)&lt;/li&gt;
&lt;li&gt;You want the smoothest possible scrolling for very large datasets&lt;/li&gt;
&lt;li&gt;Dynamic height items cause issues with FlashList&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decision Checklist for Production React Native Lists
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Production symptom or constraint&lt;/th&gt;
&lt;th&gt;Start with&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;Short settings screens, simple notifications, or fewer than a few hundred rows&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FlatList&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The built-in API is enough, and avoiding another dependency is a real advantage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visible blank flashes during fast scroll&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FlashList&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recycling reduces create/destroy churn and is the safest upgrade for most existing React Native apps.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large feeds with mixed cards, ads, and separators&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FlashList&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;estimatedItemSize&lt;/code&gt; plus &lt;code&gt;getItemType&lt;/code&gt; gives predictable recycler pools without requiring New Architecture.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chat, media feeds, or infinite content where scroll quality is product-critical&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;LegendList&lt;/strong&gt; if New Architecture is enabled; otherwise &lt;strong&gt;FlashList&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;LegendList has the highest ceiling, but its Fabric requirement changes the rollout plan.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App still depends on old-bridge native modules&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FlashList&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LegendList should wait until the dependency graph is New Architecture-ready.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sectioned lists are the main use case&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;FlatList / SectionList first&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native SectionList support is still simpler than recreating section behavior in a recycler.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical migration path is usually FlatList optimization first, FlashList second, LegendList only after the app is already on New Architecture. Skipping straight to a new list library can hide item-component bugs that memoization and stable keys would have caught.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rollout and QA Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Profile the current FlatList with real production item shapes, not placeholder rows.&lt;/li&gt;
&lt;li&gt;Fix obvious FlatList issues first: stable &lt;code&gt;keyExtractor&lt;/code&gt;, memoized &lt;code&gt;renderItem&lt;/code&gt;, &lt;code&gt;getItemLayout&lt;/code&gt; for fixed-height rows, and image sizing.&lt;/li&gt;
&lt;li&gt;Migrate one high-traffic screen to FlashList and choose an &lt;code&gt;estimatedItemSize&lt;/code&gt; from measured average row height.&lt;/li&gt;
&lt;li&gt;Test fast flings, pull-to-refresh, pagination, inverted chat lists, and mixed item types on a mid-range Android device.&lt;/li&gt;
&lt;li&gt;Watch for stale local component state after recycling; item components must reset from props when reused.&lt;/li&gt;
&lt;li&gt;If evaluating LegendList, verify New Architecture readiness across navigation, gesture, animation, and native-module dependencies before rollout.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For adjacent mobile stack choices, compare &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;a href="https://www.pkgpulse.com/guides/react-native-skia-vs-react-native-svg-vs-react-native-2026" rel="noopener noreferrer"&gt;React Native Skia vs SVG&lt;/a&gt;, and &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;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecosystem and Community Health
&lt;/h2&gt;

&lt;p&gt;FlashList is the most mature of the three non-built-in options. Shopify built it to replace FlatList in their own apps — including the Shopify app, which handles merchant catalogs with thousands of product variants — and open-sourced it with 4.4k GitHub stars. The library is actively maintained, has a dedicated issues tracker, and integrates seamlessly with Expo. Because Shopify uses it at real production scale, regressions tend to be caught quickly and fixed promptly.&lt;/p&gt;

&lt;p&gt;FlatList will never go away because it's part of React Native core. The React Native team at Meta and Microsoft continues to improve it, but the fundamental architecture — create and destroy component instances as they scroll — cannot be changed without breaking backward compatibility. FlatList is what you get by default, and it works well enough that millions of production apps rely on it for lists that don't push performance limits.&lt;/p&gt;

&lt;p&gt;LegendList comes from the makers of Legend State, a high-performance React state management library that uses Signals-like reactivity. Jay Meistrich, the creator, built LegendList specifically to eliminate the remaining scroll performance issues that FlashList doesn't fully address on the new React Native architecture. The library is newer — around 1.5k GitHub stars — but growing rapidly as Fabric adoption increases. The constraint is hard: LegendList requires New Architecture. If any of your dependencies still require the old bridge, LegendList is not yet an option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Adoption and Production Use Cases
&lt;/h2&gt;

&lt;p&gt;Shopify's primary app uses FlashList for the product catalog, order history, and customer lists — contexts where merchants may have thousands of items. The 5-10x performance improvement over FlatList was the original motivation for building FlashList in the first place. After open-sourcing in 2022, it was adopted rapidly across the React Native ecosystem. For the navigation patterns that typically host these list views, see &lt;a href="https://www.pkgpulse.com/guides/expo-router-vs-react-navigation-vs-solito-react-native-2026" rel="noopener noreferrer"&gt;Expo Router vs React Navigation vs Solito&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Discord's mobile app, which uses React Native for significant portions of its interface, uses FlashList-style recycling for message lists. Chat applications are among the most demanding list scenarios because messages have highly variable heights (short one-liners vs long code blocks), content is constantly being added at the bottom, and the list must remain scrolled to the latest message. FlashList handles this case significantly better than FlatList. For styling these list items consistently across platforms, see &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 React Native styling 2026&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For apps targeting the absolute bleeding edge of React Native performance — native module developers, startups building on Fabric from the start — LegendList is gaining traction. Early benchmarks published by the React Native community show LegendList achieving sustained 60fps even on mid-range Android devices when scrolling 10,000-item lists at maximum speed, something that FlashList occasionally drops frames on when items have complex nested components.&lt;/p&gt;

&lt;p&gt;FlatList remains the correct choice for a large category of real-world apps. Any list that comfortably renders under 300-400 items will work fine with FlatList, and the zero-dependency, zero-configuration story is genuinely valuable for apps that prioritize simplicity. Feature announcement lists, settings screens, notification feeds with daily batches — these don't need recycling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience Deep Dive
&lt;/h2&gt;

&lt;p&gt;The FlashList migration from FlatList is nearly frictionless. The API is intentionally compatible — replace the import, add &lt;code&gt;estimatedItemSize&lt;/code&gt;, remove a few FlatList-only props, and you're done. The &lt;code&gt;estimatedItemSize&lt;/code&gt; prop is the one thing developers get wrong: it should be a realistic average item height in pixels, not an extreme. If your items average 120px but you provide &lt;code&gt;estimatedItemSize={40}&lt;/code&gt;, FlashList will recalculate layouts frequently, reducing the performance benefit. The FlashList website includes a warning in the output when you're running development mode if the estimate is significantly off.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getItemType&lt;/code&gt; prop is the other FlashList-specific concept worth understanding. If your list contains multiple item types (headers, regular items, ads, loading skeletons), &lt;code&gt;getItemType&lt;/code&gt; tells FlashList which pool to recycle from. Without it, FlashList might try to recycle a header component into a regular item slot, causing visual glitches. The TypeScript types for this API are good — TypeScript will catch most mistakes at compile time.&lt;/p&gt;

&lt;p&gt;LegendList's API adds a few new concepts: &lt;code&gt;recycleItems&lt;/code&gt; is a boolean that enables the core recycling behavior, and &lt;code&gt;maintainScrollAtEnd&lt;/code&gt; keeps the viewport pinned to the newest item when new data is appended at the bottom — essential for chat applications. The Fabric requirement means you need to be already running on New Architecture, which requires &lt;code&gt;newArchEnabled: true&lt;/code&gt; in your &lt;code&gt;gradle.properties&lt;/code&gt; and Podfile. If you're using Expo, this is a single toggle in &lt;code&gt;app.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;TypeScript support across all three is solid. FlatList ships with React Native's own type definitions. FlashList provides comprehensive TypeScript types including the generic item type parameter &lt;code&gt;FlashList&amp;lt;T&amp;gt;&lt;/code&gt;. LegendList similarly provides full generics support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Benchmarks
&lt;/h2&gt;

&lt;p&gt;Based on community-published benchmarks scrolling a 10,000-item list on a mid-range Android device (Pixel 5), the frame rate differences are substantial:&lt;/p&gt;

&lt;p&gt;FlatList, unoptimized: drops to 20-30fps during fast scrolling, with visible blank flashes during rapid flings. Even with full optimization (memoization, &lt;code&gt;getItemLayout&lt;/code&gt;, &lt;code&gt;removeClippedSubviews&lt;/code&gt;), FlatList tops out around 40-50fps during aggressive scrolling.&lt;/p&gt;

&lt;p&gt;FlashList on the same device maintains 58-60fps for most scrolling patterns. Blank flashes are rare — visible primarily during very fast flings on lists with complex images that need network fetching. Memory usage stays stable at around 150MB for 10,000 items compared to FlatList's 300-400MB as it accumulates destroyed component instances.&lt;/p&gt;

&lt;p&gt;LegendList on the New Architecture achieves a genuinely different baseline: 60fps is the floor, not the ceiling. The JSI bridge eliminates the serialization overhead between JavaScript and the native layer, and Fabric's synchronous rendering means layout calculations happen in the same frame as interaction. For content-heavy feeds where each item contains images, text, and interactive elements, LegendList is measurably better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started and Migration Guide
&lt;/h2&gt;

&lt;p&gt;To migrate an existing FlatList to FlashList: install &lt;code&gt;@shopify/flash-list&lt;/code&gt; via Expo or npm, swap the import, add &lt;code&gt;estimatedItemSize&lt;/code&gt; with a realistic value, and remove &lt;code&gt;removeClippedSubviews&lt;/code&gt;, &lt;code&gt;maxToRenderPerBatch&lt;/code&gt;, and &lt;code&gt;windowSize&lt;/code&gt; props — FlashList manages these internally. Run your app and check the yellow warning in development mode if the estimated size is too far off.&lt;/p&gt;

&lt;p&gt;To try LegendList: first confirm you're on New Architecture (check for &lt;code&gt;newArchEnabled: true&lt;/code&gt; in your build config), then &lt;code&gt;npm install @legendapp/list&lt;/code&gt;, swap the import, add &lt;code&gt;estimatedItemSize&lt;/code&gt;, and add &lt;code&gt;recycleItems&lt;/code&gt;. Test your existing item components carefully after enabling recycling — stateful components that don't reset on prop changes will show stale content when recycled into a new item slot. Use &lt;code&gt;useCallback&lt;/code&gt; and proper key management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Verdict 2026
&lt;/h2&gt;

&lt;p&gt;Use &lt;strong&gt;FlatList&lt;/strong&gt; for lists under 200-300 items where performance is acceptable in testing. The zero-setup story is genuinely valuable for early-stage apps, and FlatList handles SectionList use cases that FlashList doesn't yet match.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;FlashList&lt;/strong&gt; for any list that shows performance problems — blank flashes, scroll jank, high memory usage. The migration is 15 minutes for a typical FlatList, and the performance improvement is immediate and dramatic. This should be the default choice for any production React Native app with meaningful list content.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;LegendList&lt;/strong&gt; if you're building on New Architecture and need the smoothest possible scrolling. If you're building a high-performance content feed, chat application, or media browser where list quality is a core product differentiator, LegendList represents the current ceiling for React Native list performance.&lt;/p&gt;

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

&lt;p&gt;Data sourced from official FlashList documentation (shopify.github.io/flash-list), LegendList documentation (legendapp.com), community benchmarks published on Twitter/X by React Native engineers, GitHub star counts as of February 2026, and performance reports from the React Native Discord. FlatList behavior documented from the official React Native docs and community reports on GitHub issues.&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://www.pkgpulse.com/guides/best-realtime-libraries-2026" rel="noopener noreferrer"&gt;Best Real-Time Libraries 2026&lt;/a&gt;, &lt;a href="https://www.pkgpulse.com/guides/best-nodejs-background-job-libraries-2026" rel="noopener noreferrer"&gt;Best Node.js Background Job Libraries 2026&lt;/a&gt;, &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;/p&gt;




&lt;p&gt;Read the original guide on &lt;a href="https://www.pkgpulse.com/guides/flashlist-vs-flatlist-vs-legendlist-react-native-lists-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Best Generative AI Courses 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 21 Oct 2026 16:00:59 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/best-generative-ai-courses-2026-292f</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/best-generative-ai-courses-2026-292f</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/best-generative-ai-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;Generative AI engineering is the most in-demand technical skill of 2026. Hiring data tells the story: job postings requiring LLM engineering skills have grown 340% since early 2024, and median compensation for developers who can build production applications on top of foundation models now exceeds $185,000 in the US. The demand is not for people who can use ChatGPT. It is for engineers who can build with large language models — designing RAG pipelines, fine-tuning open-source models, orchestrating agent workflows, and deploying reliable AI systems at scale.&lt;/p&gt;

&lt;p&gt;This is a distinct discipline from traditional machine learning. Classical ML focuses on training models from structured data — regression, classification, clustering. Generative AI engineering assumes the foundation model already exists (GPT-4, Claude, Llama, Gemini) and focuses on what you build on top of it. The core skill set is "LLM engineering": retrieval-augmented generation, vector databases, prompt architecture, fine-tuning with parameter-efficient methods like LoRA, agent frameworks like LangGraph, and the evaluation infrastructure required to ship AI products that actually work.&lt;/p&gt;

&lt;p&gt;The course landscape has caught up to the demand. Here are the best generative AI courses available in 2026, ranked by depth, practical value, and community recommendation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Picks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Best Course&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best overall&lt;/td&gt;
&lt;td&gt;Generative AI with LLMs (DeepLearning.AI + AWS, Coursera)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best free&lt;/td&gt;
&lt;td&gt;LangChain Academy (LangChain, free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for RAG&lt;/td&gt;
&lt;td&gt;Full Stack LLM Bootcamp (FSDL, free on YouTube)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for fine-tuning&lt;/td&gt;
&lt;td&gt;Hugging Face NLP Course (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for LLM app dev&lt;/td&gt;
&lt;td&gt;Weights &amp;amp; Biases courses (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for theory&lt;/td&gt;
&lt;td&gt;fast.ai Practical Deep Learning (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What Generative AI Engineering Covers
&lt;/h2&gt;

&lt;p&gt;This is not prompt engineering. It is not using ChatGPT to write emails. And it is not traditional machine learning.&lt;/p&gt;

&lt;p&gt;Generative AI engineering is the discipline of building production-grade applications powered by large language models. The technical surface includes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval-Augmented Generation (RAG):&lt;/strong&gt; Connecting LLMs to external knowledge — documents, databases, APIs — so they can answer questions grounded in real, current data rather than relying solely on training data. This involves chunking strategies, embedding models, vector databases (Pinecone, Weaviate, Chroma, pgvector), retrieval ranking, and hybrid search.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fine-tuning:&lt;/strong&gt; Adapting pre-trained models for specific domains or tasks using techniques like LoRA, QLoRA, and full-parameter fine-tuning. This matters when prompt engineering alone cannot achieve the required quality, latency, or cost targets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent architectures:&lt;/strong&gt; Building LLM systems that can reason, plan, use tools, and complete multi-step tasks. Frameworks like LangGraph, CrewAI, and the OpenAI Assistants API define agent loops, tool calling, and state management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluation and testing:&lt;/strong&gt; The hardest unsolved problem in LLM engineering. Building evaluation harnesses, human-in-the-loop feedback systems, and automated quality checks that catch regressions before they reach users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production deployment:&lt;/strong&gt; Model serving, caching, rate limiting, cost management, observability, and the infrastructure required to run LLM applications reliably at scale.&lt;/p&gt;

&lt;p&gt;If you want courses focused on using AI tools productively, see the &lt;a href="https://www.coursefacts.com/guides/best-ai-chatgpt-courses-2026" rel="noopener noreferrer"&gt;best AI and ChatGPT courses guide&lt;/a&gt;. For prompt writing specifically, see the &lt;a href="https://www.coursefacts.com/guides/best-prompt-engineering-courses-2026" rel="noopener noreferrer"&gt;best prompt engineering courses&lt;/a&gt;. For traditional ML foundations, see the &lt;a href="https://www.coursefacts.com/guides/best-machine-learning-courses-2026" rel="noopener noreferrer"&gt;best machine learning courses&lt;/a&gt;. This guide focuses on building with generative AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Generative AI Courses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Generative AI with LLMs — DeepLearning.AI + AWS (&lt;a href="https://www.coursefacts.com/platform/coursera" rel="noopener noreferrer"&gt;Coursera&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Duration:&lt;/strong&gt; ~3 weeks at 6 hrs/week | &lt;strong&gt;Rating:&lt;/strong&gt; 4.8/5 from 42,000+ reviews | &lt;strong&gt;Level:&lt;/strong&gt; Intermediate | &lt;strong&gt;Cost:&lt;/strong&gt; Coursera Plus or ~$49/month&lt;/p&gt;

&lt;p&gt;This is the most comprehensive single course on generative AI fundamentals available in 2026. Built by Andrew Ng's DeepLearning.AI team in partnership with AWS, it covers the complete lifecycle of working with large language models — from transformer architecture through deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the course covers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transformer architecture in depth — self-attention, multi-head attention, positional encoding&lt;/li&gt;
&lt;li&gt;Pre-training objectives and scaling laws (why bigger models perform better, and the limits of that)&lt;/li&gt;
&lt;li&gt;Fine-tuning with Parameter-Efficient Fine-Tuning (PEFT) methods, specifically LoRA&lt;/li&gt;
&lt;li&gt;Reinforcement Learning from Human Feedback (RLHF) — how models are aligned to human preferences&lt;/li&gt;
&lt;li&gt;Model evaluation metrics and benchmarks&lt;/li&gt;
&lt;li&gt;Deployment considerations: distillation, quantization, inference optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it leads:&lt;/strong&gt; Most generative AI courses focus on either theory or application. This one connects both — you understand why transformers work, then learn the practical techniques (PEFT, RLHF) that production teams actually use. The AWS partnership means the deployment section uses real infrastructure, not toy examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Python proficiency and basic familiarity with machine learning concepts. If you need ML foundations first, start with the &lt;a href="https://www.coursefacts.com/guides/best-machine-learning-courses-2026" rel="noopener noreferrer"&gt;Andrew Ng ML Specialization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers and ML engineers who want a rigorous, end-to-end understanding of how large language models are built, fine-tuned, and deployed. The single best starting point for generative AI engineering.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. LangChain Academy (Free)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; &lt;a href="https://academy.langchain.com" rel="noopener noreferrer"&gt;academy.langchain.com&lt;/a&gt; | &lt;strong&gt;Duration:&lt;/strong&gt; Self-paced, ~20 hours total | &lt;strong&gt;Level:&lt;/strong&gt; Intermediate | &lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/p&gt;

&lt;p&gt;LangChain Academy is the official course platform from the LangChain team — the developers behind the most widely-used LLM application framework. The curriculum focuses on LangGraph, LangChain's agent orchestration library, and covers the practical patterns that production LLM applications actually use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What LangChain Academy covers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to LangGraph: building stateful, multi-step agent workflows&lt;/li&gt;
&lt;li&gt;RAG patterns: naive RAG, advanced retrieval (re-ranking, query decomposition, hybrid search)&lt;/li&gt;
&lt;li&gt;Tool use and function calling: connecting LLMs to APIs, databases, and external systems&lt;/li&gt;
&lt;li&gt;Memory and state management: maintaining context across agent interactions&lt;/li&gt;
&lt;li&gt;Evaluation: testing and measuring agent performance&lt;/li&gt;
&lt;li&gt;Deployment with LangServe and LangSmith for observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; LangChain and LangGraph are the dominant open-source frameworks for building LLM applications in Python. Learning directly from the framework authors means you get patterns that reflect how the tools are actually designed to be used, not workarounds from six months ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Python proficiency. Familiarity with LLM APIs (OpenAI, Anthropic) is helpful but not required — the courses introduce these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who want to build production LLM applications — chatbots, RAG systems, AI agents — using the most widely-adopted framework. The best free option for hands-on generative AI engineering.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Full Stack LLM Bootcamp — FSDL (Free)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; &lt;a href="https://fullstackdeeplearning.com" rel="noopener noreferrer"&gt;fullstackdeeplearning.com&lt;/a&gt; / YouTube | &lt;strong&gt;Duration:&lt;/strong&gt; ~25 hours | &lt;strong&gt;Level:&lt;/strong&gt; Intermediate to Advanced | &lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/p&gt;

&lt;p&gt;The Full Stack LLM Bootcamp, taught by Charles Frye, Sergey Karayev, and Josh Tobin, is the most complete free course on building LLM-powered applications end-to-end. Originally delivered as an in-person bootcamp, the full lecture series is available on YouTube and covers the entire stack from prompt engineering through production deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the bootcamp covers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM foundations: how models work, prompt engineering, and structured output&lt;/li&gt;
&lt;li&gt;RAG architecture: document ingestion, chunking, embedding, retrieval, and generation&lt;/li&gt;
&lt;li&gt;Fine-tuning: when to fine-tune vs. prompt-engineer, LoRA/QLoRA workflows&lt;/li&gt;
&lt;li&gt;LLM application architecture: design patterns for chatbots, search, and agents&lt;/li&gt;
&lt;li&gt;Evaluation and testing: building evals, human feedback loops, monitoring quality&lt;/li&gt;
&lt;li&gt;UX design for AI products: how to build interfaces for non-deterministic outputs&lt;/li&gt;
&lt;li&gt;Deployment and operations: serving, caching, cost management, observability&lt;/li&gt;
&lt;li&gt;Security: prompt injection, data leakage, and adversarial attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it stands out:&lt;/strong&gt; The bootcamp is project-oriented rather than lecture-oriented. Each session builds toward a complete, deployable application. The instructors are practitioners (Frye is a researcher at Modal, Karayev and Tobin founded Weights &amp;amp; Biases and Gantry respectively), so the content reflects real production decisions rather than academic abstractions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Strong Python skills and basic ML familiarity. This is not a beginner course.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Experienced developers who want the full picture of LLM application development — architecture, evaluation, deployment, and operations. The closest thing to a free LLM engineering bootcamp.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Hugging Face NLP Course (Free)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; &lt;a href="https://huggingface.co/learn/nlp-course" rel="noopener noreferrer"&gt;huggingface.co/learn/nlp-course&lt;/a&gt; | &lt;strong&gt;Duration:&lt;/strong&gt; Self-paced, ~30 hours | &lt;strong&gt;Level:&lt;/strong&gt; Intermediate | &lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/p&gt;

&lt;p&gt;The Hugging Face NLP Course is the standard curriculum for working with the open-source transformer ecosystem. Originally focused on NLP, the course has expanded to cover the full range of transformer-based generative AI — including fine-tuning, tokenization, and the Hugging Face Hub infrastructure that hosts virtually every major open-source model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the course covers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transformer architecture: encoders, decoders, and encoder-decoder models&lt;/li&gt;
&lt;li&gt;Tokenizers: BPE, WordPiece, SentencePiece — understanding how text becomes tokens&lt;/li&gt;
&lt;li&gt;The Hugging Face Transformers library: pipelines, model loading, inference&lt;/li&gt;
&lt;li&gt;Fine-tuning with the Trainer API: adapting pre-trained models for custom tasks&lt;/li&gt;
&lt;li&gt;The Datasets library: loading, preprocessing, and managing training data&lt;/li&gt;
&lt;li&gt;Model Hub: sharing, versioning, and deploying models&lt;/li&gt;
&lt;li&gt;Accelerate and PEFT: efficient training on consumer hardware&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; The Hugging Face Hub is where open-source AI lives. Llama, Mistral, Gemma, Phi, Qwen — nearly every significant open-source model is distributed through the Hub. Understanding the Hugging Face ecosystem is a prerequisite for any work with open-source models, whether you are fine-tuning, running local inference, or contributing to the community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Python and PyTorch basics. Some familiarity with deep learning concepts is helpful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who want to fine-tune and work with open-source models. If your generative AI work involves anything beyond commercial APIs — local inference, custom fine-tuning, model evaluation — this course is essential.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Weights &amp;amp; Biases Courses (Free)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; &lt;a href="https://www.wandb.ai/courses" rel="noopener noreferrer"&gt;wandb.ai/courses&lt;/a&gt; | &lt;strong&gt;Duration:&lt;/strong&gt; 2-5 hours per course | &lt;strong&gt;Level:&lt;/strong&gt; Intermediate | &lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/p&gt;

&lt;p&gt;Weights &amp;amp; Biases (W&amp;amp;B) offers a growing catalog of free courses that approach generative AI from an MLOps and evaluation perspective — the production side that most courses skip. The courses are taught by W&amp;amp;B engineers and guest instructors who build LLM tooling for a living.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key courses in the catalog:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Building LLM-Powered Apps:&lt;/strong&gt; End-to-end development of LLM applications with proper experiment tracking, including RAG pipelines and chatbot architectures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluating and Debugging Generative AI:&lt;/strong&gt; How to build evaluation harnesses for LLM outputs — the most underserved topic in generative AI education&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training and Fine-Tuning LLMs:&lt;/strong&gt; Practical fine-tuning workflows with experiment tracking, loss monitoring, and model comparison&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Engineering: Structured Outputs:&lt;/strong&gt; Forcing LLMs to produce reliable, parseable output for production systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why these courses matter:&lt;/strong&gt; Evaluation is the bottleneck in production generative AI. Most teams can build a demo RAG system in a weekend. The hard part is knowing whether it works reliably, catching regressions, and improving quality over time. The W&amp;amp;B courses address this gap directly with practical tooling rather than abstract advice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Python and basic familiarity with LLM APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who are past the "build a demo" stage and need to ship reliable, measurable LLM applications. The evaluation and debugging course alone fills a gap that no other free resource covers as well.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. fast.ai Practical Deep Learning for Coders (Free)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Platform:&lt;/strong&gt; &lt;a href="https://course.fast.ai" rel="noopener noreferrer"&gt;course.fast.ai&lt;/a&gt; | &lt;strong&gt;Duration:&lt;/strong&gt; ~7 weeks | &lt;strong&gt;Level:&lt;/strong&gt; Intermediate | &lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/p&gt;

&lt;p&gt;Jeremy Howard's fast.ai course has been one of the most influential ML courses since 2016, and the current edition covers generative AI extensively. The course's top-down teaching philosophy — build a working application first, understand the theory later — makes it uniquely effective for developers who learn by doing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What fast.ai covers for generative AI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transformer architecture built from scratch in PyTorch&lt;/li&gt;
&lt;li&gt;Stable Diffusion and image generation: how diffusion models work, not just how to use them&lt;/li&gt;
&lt;li&gt;Language models: training a GPT-style model from scratch at small scale&lt;/li&gt;
&lt;li&gt;Fine-tuning: adapting pre-trained models for custom tasks using the fastai and Hugging Face libraries&lt;/li&gt;
&lt;li&gt;Deployment: shipping models via Hugging Face Spaces and Gradio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The fast.ai difference:&lt;/strong&gt; Most generative AI courses teach you to use frameworks and APIs. fast.ai teaches you to build the components yourself. By implementing attention, building a language model from scratch, and training a diffusion model step by step, you develop the architectural intuition that separates engineers who can debug production AI systems from those who can only follow tutorials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Python proficiency. The course starts from foundations but moves quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who want deep architectural understanding of generative models — not just how to call APIs, but how the models actually work. The best option for building the theoretical foundation that makes everything else easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Generative AI Concepts to Master
&lt;/h2&gt;

&lt;p&gt;Regardless of which courses you take, these are the core concepts that define generative AI engineering competence in 2026:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transformer architecture.&lt;/strong&gt; Self-attention, multi-head attention, feed-forward layers, layer normalization. You do not need to implement transformers from scratch for most jobs, but you need to understand why they work and how architectural choices (context window, number of layers, attention heads) affect model behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attention mechanisms.&lt;/strong&gt; The computational core of modern LLMs. Understanding attention explains why models struggle with long contexts, why RAG works, and how fine-tuning changes model behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval-Augmented Generation (RAG).&lt;/strong&gt; The most common production pattern for LLM applications. Embedding documents into vector space, retrieving relevant chunks at query time, and generating grounded responses. The difference between a demo RAG system and a production one involves chunking strategy, retrieval ranking, hybrid search, and evaluation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vector databases.&lt;/strong&gt; Pinecone, Weaviate, Chroma, Qdrant, pgvector. These are the infrastructure layer for RAG and semantic search. Understanding tradeoffs between hosted vs. self-managed, approximate vs. exact nearest neighbor, and metadata filtering is practical knowledge for any LLM engineer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fine-tuning (LoRA, QLoRA).&lt;/strong&gt; Parameter-efficient fine-tuning lets you adapt foundation models for specific tasks or domains without the compute cost of full-parameter training. LoRA (Low-Rank Adaptation) and its quantized variant QLoRA are the standard techniques in 2026, reducing the hardware requirements from clusters of A100s to a single consumer GPU.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent frameworks.&lt;/strong&gt; LangGraph, CrewAI, AutoGen, and the OpenAI Assistants API define how LLMs reason, plan, and take actions. Agent development is where generative AI intersects with software engineering — state machines, error handling, tool orchestration, and graceful degradation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluation and testing.&lt;/strong&gt; The hardest problem in LLM engineering. Automated evaluation (LLM-as-judge, reference-based scoring), human evaluation workflows, regression testing for prompt changes, and monitoring production quality over time. This is the skill most courses underserve and most teams need.&lt;/p&gt;




&lt;h2&gt;
  
  
  Generative AI Learning Path
&lt;/h2&gt;

&lt;p&gt;A structured progression from foundations to production-ready generative AI engineering:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Foundations (1-2 months)&lt;/strong&gt;&lt;br&gt;
Build &lt;a href="https://www.coursefacts.com/guides/best-python-courses-2026" rel="noopener noreferrer"&gt;Python proficiency&lt;/a&gt; and basic ML literacy. You do not need to be an ML expert, but you need to understand what a model is, what training does, and how prediction works. Andrew Ng's &lt;a href="https://www.coursefacts.com/guides/best-machine-learning-courses-2026" rel="noopener noreferrer"&gt;ML Specialization&lt;/a&gt; is the standard recommendation for this foundation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Transformer Theory (2-3 weeks)&lt;/strong&gt;&lt;br&gt;
Understand the architecture that powers every modern LLM. The Generative AI with LLMs course (Coursera) or the relevant fast.ai lessons cover this. Focus on attention mechanisms, tokenization, and pre-training objectives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Prompt Engineering (1-2 weeks)&lt;/strong&gt;&lt;br&gt;
Learn structured prompting, few-shot learning, chain-of-thought, and system prompt design. The &lt;a href="https://www.coursefacts.com/guides/best-prompt-engineering-courses-2026" rel="noopener noreferrer"&gt;best prompt engineering courses&lt;/a&gt; cover this thoroughly. This phase is short but essential — prompt engineering is a prerequisite for everything that follows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: RAG Pipelines (3-4 weeks)&lt;/strong&gt;&lt;br&gt;
Build retrieval-augmented generation systems. LangChain Academy and the Full Stack LLM Bootcamp are the best resources. Build at least one complete RAG application with a real document corpus — not a toy example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 5: Fine-Tuning (2-3 weeks)&lt;/strong&gt;&lt;br&gt;
Learn when and how to fine-tune models. The Hugging Face NLP Course covers the mechanics. Focus on LoRA/QLoRA workflows and understanding when fine-tuning is the right solution vs. better prompting or RAG.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 6: Agent Development (3-4 weeks)&lt;/strong&gt;&lt;br&gt;
Build multi-step agent systems with tool use. LangChain Academy's LangGraph courses and the &lt;a href="https://www.coursefacts.com/guides/best-ai-engineering-courses-developers-2026" rel="noopener noreferrer"&gt;AI engineering courses&lt;/a&gt; cover agent patterns. Build an agent that uses multiple tools to complete a real task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 7: Production Deployment (ongoing)&lt;/strong&gt;&lt;br&gt;
Evaluation, monitoring, cost optimization, and operational excellence. The W&amp;amp;B courses and Full Stack LLM Bootcamp address this. Ship a production application and maintain it — this is where the real learning happens.&lt;/p&gt;

&lt;p&gt;Total timeline: 5-7 months of focused study, assuming 10-15 hours per week and existing programming experience. The path is faster if you already have ML foundations, slower if you are starting from scratch with Python.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;For a comprehensive foundation:&lt;/strong&gt; Generative AI with LLMs (DeepLearning.AI + AWS, Coursera) is the best single course for understanding how large language models work and how to fine-tune them. Start here if you want depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For hands-on LLM app development:&lt;/strong&gt; LangChain Academy is the best free option for building production RAG systems and AI agents. It teaches the patterns you will actually use at work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the full stack:&lt;/strong&gt; The Full Stack LLM Bootcamp (FSDL, free on YouTube) covers the entire lifecycle from architecture through deployment. The best free resource for experienced developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For open-source models:&lt;/strong&gt; The Hugging Face NLP Course is essential if your work involves anything beyond commercial APIs — fine-tuning, local inference, or contributing to open-source AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For evaluation and production quality:&lt;/strong&gt; The Weights &amp;amp; Biases courses fill the most critical gap in generative AI education. Every team ships the demo. The hard part is shipping something reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest assessment:&lt;/strong&gt; Generative AI engineering is a fast-moving field. Courses from even 12 months ago may teach deprecated patterns or outdated frameworks. The courses on this list are maintained by the teams building the tools — LangChain, Hugging Face, Weights &amp;amp; Biases, DeepLearning.AI — which is why they stay current. Prioritize courses from framework authors, supplement with project-based learning, and build something real as soon as possible. The gap between "completed a course" and "shipped an LLM application" is where actual competence develops.&lt;/p&gt;




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

</description>
    </item>
    <item>
      <title>GitHub Actions vs CircleCI vs GitLab CI 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 14 Oct 2026 16:00:40 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/github-actions-vs-circleci-vs-gitlab-ci-2026-1mc1</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/github-actions-vs-circleci-vs-gitlab-ci-2026-1mc1</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.pkgpulse.com/guides/github-actions-vs-circleci-vs-gitlab-ci-cicd-platforms-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;&lt;strong&gt;GitHub Actions&lt;/strong&gt; is the natural default for repositories already on GitHub. &lt;strong&gt;CircleCI&lt;/strong&gt; is strongest when teams need granular resource classes, test splitting, and interactive SSH debugging. &lt;strong&gt;GitLab CI&lt;/strong&gt; fits teams that want CI/CD inside a broader GitLab DevSecOps workflow. &lt;strong&gt;Semaphore&lt;/strong&gt; remains an unranked fourth shortlist candidate for transparent hosted-compute pricing, an open-source self-hosted control plane, and MCP-based CI context. No provider is universally fastest or most complete: benchmark your own repository and check the plan and edition that contains the features you need.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt;: Tight GitHub integration, a large public Actions marketplace, and standard hosted runners free for public repositories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CircleCI&lt;/strong&gt;: Timing-based test splitting, configurable resource classes, Docker layer caching, and SSH debugging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitLab CI&lt;/strong&gt;: Integrated source control, registry, deployment, and plan-dependent security/compliance capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semaphore&lt;/strong&gt;: A reasonable fourth candidate for pay-as-you-go compute, Community Edition self-hosting, or MCP-assisted CI investigation&lt;/li&gt;
&lt;li&gt;Treat ecosystem-size, speed, caching, and completeness claims as workload- and plan-specific rather than universal rankings&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Comparison Matrix
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Pricing and allowances checked August 11, 2026. Vendor pages can change; confirm them before purchase.&lt;/em&gt;&lt;/p&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;GitHub Actions&lt;/th&gt;
&lt;th&gt;CircleCI&lt;/th&gt;
&lt;th&gt;GitLab CI&lt;/th&gt;
&lt;th&gt;Semaphore&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Entry allowance&lt;/td&gt;
&lt;td&gt;GitHub Free: 2,000 private-repo min/month; standard runners free for public repos&lt;/td&gt;
&lt;td&gt;Free: 30,000 credits/month, advertised as 6,000 build min&lt;/td&gt;
&lt;td&gt;Free: 400 compute min/month, up to 5 licensed users&lt;/td&gt;
&lt;td&gt;$15 monthly credits, about 2,000 Ubuntu x64 2-vCPU min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entry paid context&lt;/td&gt;
&lt;td&gt;Usage beyond plan allowance; baseline Linux example is $0.006/min&lt;/td&gt;
&lt;td&gt;Performance starts at $15/month&lt;/td&gt;
&lt;td&gt;Premium: $29/user/month billed annually; extra compute is $10/1,000 min&lt;/td&gt;
&lt;td&gt;Ubuntu x64 2-vCPU: $0.0075/min; support sold separately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-hosted execution&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅; CE and EE also self-host the control plane&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker support&lt;/td&gt;
&lt;td&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;Reusable ecosystem&lt;/td&gt;
&lt;td&gt;Actions marketplace&lt;/td&gt;
&lt;td&gt;Orbs&lt;/td&gt;
&lt;td&gt;Templates/includes&lt;/td&gt;
&lt;td&gt;Templates and examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native VCS position&lt;/td&gt;
&lt;td&gt;Built into GitHub&lt;/td&gt;
&lt;td&gt;Standalone; GitHub/GitLab/Bitbucket integrations&lt;/td&gt;
&lt;td&gt;Built into GitLab&lt;/td&gt;
&lt;td&gt;Standalone; GitHub/GitLab/Bitbucket support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ hosted Ubuntu ARM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approval/deployment gates&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Cloud/EE; CE lacks deployment targets and promotions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OIDC for cloud auth&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Cloud/EE; not CE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  GitHub Actions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; — CI/CD for GitHub:&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Node.js workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/ci.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&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;18&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20&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="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/checkout@v4&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="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pnpm"&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;pnpm install --frozen-lockfile&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;pnpm run lint&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;pnpm run typecheck&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;pnpm run test --coverage&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/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;if&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="m"&gt;20&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage/&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&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/checkout@v4&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="m"&gt;20&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pnpm"&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;pnpm install --frozen-lockfile&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;pnpm run build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/deploy.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-${{ github.ref }}&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;deployments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&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/checkout@v4&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="m"&gt;20&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pnpm"&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;pnpm install --frozen-lockfile&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;pnpm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Cloudflare Pages&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;cloudflare/wrangler-action@v3&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;apiToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CLOUDFLARE_API_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pages deploy dist --project-name=pkgpulse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reusable workflows
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/reusable-test.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reusable Test&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_call&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&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="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&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/checkout@v4&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;${{ inputs.node-version }}&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pnpm"&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;pnpm install --frozen-lockfile&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;pnpm test&lt;/span&gt;

&lt;span class="c1"&gt;# Usage in another workflow:&lt;/span&gt;
&lt;span class="c1"&gt;# jobs:&lt;/span&gt;
&lt;span class="c1"&gt;#   call-tests:&lt;/span&gt;
&lt;span class="c1"&gt;#     uses: ./.github/workflows/reusable-test.yml&lt;/span&gt;
&lt;span class="c1"&gt;#     with:&lt;/span&gt;
&lt;span class="c1"&gt;#       node-version: "22"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  CircleCI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://circleci.com" rel="noopener noreferrer"&gt;CircleCI&lt;/a&gt; — performance-focused CI/CD:&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .circleci/config.yml&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;

&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/node@5.2&lt;/span&gt;

&lt;span class="na"&gt;executors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node-executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cimg/node:20.11&lt;/span&gt;
    &lt;span class="na"&gt;resource_class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;medium&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-executor&lt;/span&gt;
    &lt;span class="na"&gt;parallelism&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&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="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;node/install-packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;pkg-manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm run lint&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Type Check&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm run typecheck&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test (parallel)&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;TESTS=$(circleci tests glob "tests/**/*.test.ts" | circleci tests split --split-by=timings)&lt;/span&gt;
            &lt;span class="s"&gt;pnpm run test $TESTS&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-results&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;

  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-executor&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="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;node/install-packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;pkg-manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm&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;pnpm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;persist_to_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;dist&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-executor&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;attach_workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx wrangler pages deploy dist&lt;/span&gt;

&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ci-cd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Advanced caching
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-executor&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="s"&gt;checkout&lt;/span&gt;

      &lt;span class="c1"&gt;# Restore multiple caches:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deps-v1-{{ checksum "pnpm-lock.yaml" }}&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deps-v1-&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;pnpm install --frozen-lockfile&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deps-v1-{{ checksum "pnpm-lock.yaml" }}&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;~/.pnpm-store&lt;/span&gt;

      &lt;span class="c1"&gt;# Docker layer caching (paid feature):&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;setup_remote_docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;docker_layer_caching&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;docker build -t pkgpulse .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Orbs (reusable packages)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;

&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/node@5.2&lt;/span&gt;
  &lt;span class="na"&gt;aws-cli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/aws-cli@4.1&lt;/span&gt;
  &lt;span class="na"&gt;slack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/slack@4.12&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-executor&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="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;node/install-packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;pkg-manager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm&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;pnpm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws-cli/setup&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to S3&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 sync dist/ s3://pkgpulse-prod/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;slack/notify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pass&lt;/span&gt;
          &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;basic_success_1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  GitLab CI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.gitlab.com/ee/ci/" rel="noopener noreferrer"&gt;GitLab CI&lt;/a&gt; — all-in-one DevOps CI/CD:&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic pipeline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .gitlab-ci.yml&lt;/span&gt;
&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;

&lt;span class="na"&gt;variables&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;

&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:${NODE_VERSION}&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm-lock.yaml&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.pnpm-store/&lt;/span&gt;

&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;corepack enable&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm install --frozen-lockfile&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm run lint&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm run typecheck&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm run test --coverage&lt;/span&gt;
  &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/All&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files[^|]*\|[^|]*\s+([\d\.]+)/'&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;coverage_report&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;coverage_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cobertura&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage/cobertura-coverage.xml&lt;/span&gt;
      &lt;span class="na"&gt;junit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-results/junit.xml&lt;/span&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;corepack enable&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm install --frozen-lockfile&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pnpm run build&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dist/&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 week&lt;/span&gt;

&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx wrangler pages deploy dist&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://pkgpulse.com&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == "main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Security scanning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Built-in security scanning:&lt;/span&gt;
&lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security/SAST.gitlab-ci.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security/Dependency-Scanning.gitlab-ci.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security/Secret-Detection.gitlab-ci.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security/Container-Scanning.gitlab-ci.yml&lt;/span&gt;

&lt;span class="c1"&gt;# These run automatically:&lt;/span&gt;
&lt;span class="c1"&gt;# - SAST: Static Application Security Testing&lt;/span&gt;
&lt;span class="c1"&gt;# - Dependency scanning: Check npm for vulnerabilities&lt;/span&gt;
&lt;span class="c1"&gt;# - Secret detection: Find leaked secrets&lt;/span&gt;
&lt;span class="c1"&gt;# - Container scanning: Scan Docker images&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multi-environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-staging&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-production&lt;/span&gt;

&lt;span class="na"&gt;deploy-staging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-staging&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx wrangler pages deploy dist --branch staging&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://staging.pkgpulse.com&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_MERGE_REQUEST_ID&lt;/span&gt;

&lt;span class="na"&gt;deploy-production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-production&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npx wrangler pages deploy dist&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://pkgpulse.com&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == "main"&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;  &lt;span class="c1"&gt;# Require manual approval&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Child pipelines and includes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .gitlab-ci.yml&lt;/span&gt;
&lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.gitlab/ci/test.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.gitlab/ci/build.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.gitlab/ci/deploy.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;shared/ci-templates'&lt;/span&gt;
    &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/templates/node-pipeline.yml'&lt;/span&gt;

&lt;span class="c1"&gt;# Dynamic child pipelines:&lt;/span&gt;
&lt;span class="na"&gt;generate-pipeline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prepare&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node scripts/generate-ci.js &amp;gt; child-pipeline.yml&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;child-pipeline.yml&lt;/span&gt;

&lt;span class="na"&gt;run-dynamic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;child-pipeline.yml&lt;/span&gt;
        &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;generate-pipeline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cost Breakdown for Real Workloads
&lt;/h2&gt;

&lt;p&gt;Pricing models differ significantly, so compare the same operating system, CPU/RAM class, concurrency, storage, support, and expected runtime. The figures below were checked against official pricing pages on &lt;strong&gt;August 11, 2026&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/billing/concepts/product-billing/github-actions" rel="noopener noreferrer"&gt;GitHub Free includes&lt;/a&gt; 2,000 standard-runner minutes per month for private repositories, 500 MB of artifact storage, and 10 GB of cache storage per repository&lt;/li&gt;
&lt;li&gt;Standard GitHub-hosted runners remain free for public repositories; larger runners are billed separately&lt;/li&gt;
&lt;li&gt;GitHub's current billing example uses $0.006 USD/min for baseline Linux usage beyond the included allowance&lt;/li&gt;
&lt;li&gt;Self-hosted runner execution does not consume hosted-runner minutes, but you still pay for and operate the infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CircleCI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://circleci.com/pricing/" rel="noopener noreferrer"&gt;Free plan&lt;/a&gt; includes 30,000 credits per month and is advertised as 6,000 build minutes; those are not interchangeable units&lt;/li&gt;
&lt;li&gt;Credits are consumed according to resource class and other usage, so actual minutes vary; do not divide credits by a fixed rate without choosing the executor&lt;/li&gt;
&lt;li&gt;The Performance plan starts at $15/month and also includes 30,000 monthly credits; Scale is custom-priced&lt;/li&gt;
&lt;li&gt;Free, Performance, and Scale currently list 5, 20, and unlimited concurrent tasks on self-hosted runners respectively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GitLab CI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://about.gitlab.com/pricing/" rel="noopener noreferrer"&gt;GitLab.com Free&lt;/a&gt; includes 400 compute minutes per month, up to 5 licensed users, and 10 GiB storage&lt;/li&gt;
&lt;li&gt;Premium is $29 per user/month billed annually and includes 10,000 compute minutes; Ultimate is custom-priced and includes 50,000 minutes&lt;/li&gt;
&lt;li&gt;Additional instance-runner compute is listed at $10 per 1,000 minutes as a one-time purchase&lt;/li&gt;
&lt;li&gt;Self-managed runners shift compute and operational cost to your infrastructure; they do not make GitLab licensing, storage, or administration free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Semaphore:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://semaphore.io/pricing" rel="noopener noreferrer"&gt;Semaphore pricing&lt;/a&gt; includes $15 in monthly credits, described as about 2,000 Ubuntu x64 2-vCPU minutes, and 20 concurrent jobs by default&lt;/li&gt;
&lt;li&gt;Hosted Ubuntu x64 2-vCPU compute is $0.0075/min; Ubuntu ARM 2-vCPU is $0.003/min; macOS 4-vCPU is $0.09/min&lt;/li&gt;
&lt;li&gt;Self-hosted-agent execution is $0.0025/min on any machine, separate from the cost of that machine&lt;/li&gt;
&lt;li&gt;Community Edition is free to license and self-host; Cloud usage, Enterprise licensing, support plans, and your own infrastructure are separate cost decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Self-hosting changes rather than eliminates cost.&lt;/strong&gt; All four can use customer-managed execution capacity, but licensing, control-plane hosting, support, security controls, maintenance, and runner infrastructure differ. Model those items alongside build minutes before choosing a platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Notes: Ecosystem Integration &amp;amp; Secrets Management
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions marketplace:&lt;/strong&gt; The public marketplace covers major cloud providers, testing frameworks, deployment targets, and developer tools. Workflows can compose actions such as &lt;code&gt;aws-actions/configure-aws-credentials&lt;/code&gt; and &lt;code&gt;actions/setup-node&lt;/code&gt;, but teams should pin third-party actions to reviewed commit SHAs and treat marketplace code as part of their software supply chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CircleCI Orbs:&lt;/strong&gt; Orbs package reusable CircleCI commands, jobs, and executors. They are useful when a team wants shared configuration plus precise resource-class control, but orb provenance, version pinning, and plan-specific features still need review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitLab CI templates and includes:&lt;/strong&gt; GitLab CI uses &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; with &lt;code&gt;include:&lt;/code&gt; to share templates. The source, merge-request, registry, deployment, and security surfaces are most tightly integrated when a team adopts the broader GitLab platform; exact security and compliance capabilities vary by tier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secrets management:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All four platforms support encrypted project or repository secrets&lt;/li&gt;
&lt;li&gt;GitHub Actions: repository, environment, and organization secrets plus OIDC tokens&lt;/li&gt;
&lt;li&gt;CircleCI: project variables and Contexts for sharing secrets under access controls&lt;/li&gt;
&lt;li&gt;GitLab CI: project and group CI/CD variables, with protection and masking controls&lt;/li&gt;
&lt;li&gt;Semaphore: project and organization secrets in all editions; secret-access policies and OIDC are available in Cloud/EE, not CE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OIDC can reduce long-lived cloud credentials, but availability and policy controls depend on the platform plan or Semaphore edition. Use short-lived credentials, least privilege, protected environments, and explicit review for workflows that can deploy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Platform Deep Dives
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Actions in Practice
&lt;/h3&gt;

&lt;p&gt;GitHub Actions is widely used in GitHub-hosted projects because repository events, pull-request checks, environments, releases, and &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; permissions live in one system. Standard GitHub-hosted runners are free for public repositories, while private-repository allowances and larger-runner charges depend on plan. The automatic &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; reduces separate credential setup for supported GitHub operations, but its permissions still need to be minimized per workflow.&lt;/p&gt;

&lt;p&gt;Matrix strategies make it concise to test multiple Node.js versions, operating systems, or configuration combinations, with jobs fanning out in parallel subject to concurrency and plan limits. That is especially useful for libraries that publish compatibility promises across environments.&lt;/p&gt;

&lt;p&gt;Reusable workflows let organizations define shared CI logic once and call it from multiple repositories. Marketplace actions can accelerate setup, but reusable code should be reviewed, pinned, and updated deliberately rather than assumed safe because it is popular.&lt;/p&gt;

&lt;h3&gt;
  
  
  CircleCI in Practice
&lt;/h3&gt;

&lt;p&gt;CircleCI emphasizes performance tuning and debuggability. Timing-based test splitting distributes test files across parallel executors using historical data; the benefit depends on suite shape, executor startup, cache behavior, and the amount of parallelism purchased.&lt;/p&gt;

&lt;p&gt;SSH debugging is a differentiating workflow: for supported jobs, CircleCI lets an authorized user connect to the rerun job environment to investigate failures. It can shorten diagnosis for environment-specific problems, but teams should apply the same secrets and production-data controls they would to any interactive runner access.&lt;/p&gt;

&lt;p&gt;CircleCI resource classes let a job select CPU/RAM and architecture profiles. This is useful when test, container-build, and deployment jobs have different resource needs, but credit use rises with the chosen class and must be included in cost comparisons.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitLab CI in Practice
&lt;/h3&gt;

&lt;p&gt;GitLab CI's main advantage is integration with the GitLab platform: merge-request pipelines, environments, container registry, and security results can share the same project and permission model. Auto DevOps can generate a starting pipeline for supported project types, but production teams should review the generated configuration and tier requirements.&lt;/p&gt;

&lt;p&gt;GitLab maintains templates for SAST, DAST, dependency, secret, and container scanning. Scanner availability, dashboards, approvals, and compliance features vary across Free, Premium, and Ultimate; adding a template does not by itself guarantee a complete control or audit program.&lt;/p&gt;

&lt;p&gt;GitLab runners can be registered at project, group, or instance scope. This gives platform teams centralized options, while runner isolation, executor choice, patching, and cross-project trust remain operating decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing Based on Your Current Tooling
&lt;/h3&gt;

&lt;p&gt;Source-host integration is often the lowest-friction starting point: GitHub-hosted projects can evaluate Actions first, and GitLab-hosted projects can evaluate GitLab CI first. External CI can still be a better fit when test splitting, heterogeneous source hosts, self-hosted control-plane requirements, debugging workflow, compliance boundaries, or measured cost justify the additional integration.&lt;/p&gt;

&lt;p&gt;CircleCI and Semaphore should therefore be tested on their operating merits rather than dismissed because they are not the native CI for one forge. Compare switching cost, developer workflow, permissions, queue time, runner operations, and reproducible workload results—not vendor-wide performance labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Semaphore Fits
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://semaphore.io" rel="noopener noreferrer"&gt;Semaphore&lt;/a&gt; is worth evaluating as an unranked fourth shortlist candidate, especially when your decision centers on hosted-compute cost, a self-hosted control plane, or agent access to CI data rather than native source-host integration. Its &lt;a href="https://semaphore.io/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; separates compute from support and publishes per-minute Linux, macOS, and self-hosted-agent rates. That transparency is useful for modeling, but it is not proof that Semaphore will be cheaper for your workload.&lt;/p&gt;

&lt;p&gt;Semaphore's own &lt;a href="https://semaphore.io/blog/semaphore-ci-cd-benchmark-performance-and-cost-analysis" rel="noopener noreferrer"&gt;CI/CD benchmark&lt;/a&gt; is vendor-run, workload-specific evidence—not a general ranking. It used Redmine (Ruby on Rails), dependency installation plus the full test suite, warmed caches, 10 consecutive runs per provider, no removed outliers, 2-vCPU machines, and one job with no parallelism. RAM was not equal: Semaphore and GitLab used 8 GB, GitHub Actions 7 GB, and CircleCI and Buildkite 4 GB. Semaphore reported 5m01s and $0.04 per job in that setup. The public article does not identify the exact Redmine commit or publish raw job logs and the competitor pipeline configurations, so independently reproducing the comparison is limited. Run a proof of concept with the same commit, cache state, runner resources, network dependencies, and parallelism policy before drawing speed or cost conclusions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Semaphore Cloud, Community, and Enterprise
&lt;/h4&gt;

&lt;p&gt;Semaphore's &lt;a href="https://docs.semaphore.io/getting-started/features" rel="noopener noreferrer"&gt;official feature matrix&lt;/a&gt; shows meaningful edition differences; "open source" does not imply feature parity with Cloud or Enterprise.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision area&lt;/th&gt;
&lt;th&gt;Cloud&lt;/th&gt;
&lt;th&gt;Community Edition (CE)&lt;/th&gt;
&lt;th&gt;Enterprise Edition (EE)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control plane&lt;/td&gt;
&lt;td&gt;Vendor-hosted&lt;/td&gt;
&lt;td&gt;Self-hosted, &lt;a href="https://docs.semaphore.io/getting-started/install" rel="noopener noreferrer"&gt;Apache-2.0 core&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Self-hosted, licensed/source-available enterprise code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git providers&lt;/td&gt;
&lt;td&gt;GitHub, GitLab, Bitbucket&lt;/td&gt;
&lt;td&gt;Same, plus any Git server&lt;/td&gt;
&lt;td&gt;Same, plus any Git server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow controls&lt;/td&gt;
&lt;td&gt;Promotions, deployment targets, and pre-flight checks&lt;/td&gt;
&lt;td&gt;These controls are not included&lt;/td&gt;
&lt;td&gt;Included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security visibility&lt;/td&gt;
&lt;td&gt;Secret-access policies and audit logs&lt;/td&gt;
&lt;td&gt;Project/org secrets, but no secret-access policies or audit logs&lt;/td&gt;
&lt;td&gt;Secret-access policies and audit logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Identity and permissions&lt;/td&gt;
&lt;td&gt;Custom roles, user groups, SAML/SCIM, OIDC&lt;/td&gt;
&lt;td&gt;No custom roles, user groups, SAML/SCIM, or OIDC&lt;/td&gt;
&lt;td&gt;Those controls are included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operations/cost&lt;/td&gt;
&lt;td&gt;Hosted compute plus optional support&lt;/td&gt;
&lt;td&gt;You operate the control plane and runners&lt;/td&gt;
&lt;td&gt;You operate the deployment; licensing/support are separate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This makes CE plausible for teams prepared to own availability, upgrades, backups, and security operations, while Cloud or EE is the more relevant comparison when auditability, federation, policy controls, and deployment governance are requirements.&lt;/p&gt;

&lt;h4&gt;
  
  
  AI and agent context in 2026
&lt;/h4&gt;

&lt;p&gt;Semaphore is not uniquely "AI-native." Its &lt;a href="https://docs.semaphore.io/using-semaphore/ai/mcp-server" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt; can expose workflows, jobs, logs, and test results, but support must first enable MCP for the organization. OAuth 2.1 is recommended; personal or service-account API tokens are also supported. Running or rerunning workflows requires a second, separately enabled write-permission gate, so teams should start read-only and apply least privilege.&lt;/p&gt;

&lt;p&gt;Competitors now cover adjacent agent workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/copilot/concepts/agents/cloud-agent/about-cloud-agent" rel="noopener noreferrer"&gt;GitHub Copilot cloud agent&lt;/a&gt; works in a GitHub Actions-powered ephemeral environment to research code, make changes, and run tests; it requires a paid Copilot plan and can be policy-disabled&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://circleci.com/product/mcp/" rel="noopener noreferrer"&gt;CircleCI's MCP server&lt;/a&gt; exposes build logs, test results, pipeline status, analytics, and run/rerun tools through hosted OAuth2 or the authenticated CircleCI CLI&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://about.gitlab.com/pricing/" rel="noopener noreferrer"&gt;GitLab Duo Agent Platform&lt;/a&gt; is available to Premium and Ultimate customers on usage-based GitLab Credits and advertises pipeline fixes and CI/CD modernization among its agent workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare the data exposed, authentication model, mutation permissions, audit trail, plan gating, and how each agent handles untrusted build output—not just whether the vendor uses the terms AI or MCP.&lt;/p&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;GitHub Actions&lt;/th&gt;
&lt;th&gt;CircleCI&lt;/th&gt;
&lt;th&gt;GitLab CI&lt;/th&gt;
&lt;th&gt;Semaphore&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Built into&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;Standalone&lt;/td&gt;
&lt;td&gt;GitLab&lt;/td&gt;
&lt;td&gt;Standalone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config format&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;YAML / visual editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reusable components&lt;/td&gt;
&lt;td&gt;Actions marketplace&lt;/td&gt;
&lt;td&gt;Orbs&lt;/td&gt;
&lt;td&gt;Templates/includes&lt;/td&gt;
&lt;td&gt;Templates/examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel tests&lt;/td&gt;
&lt;td&gt;Matrix/jobs&lt;/td&gt;
&lt;td&gt;Timing-based splitting&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;parallel&lt;/code&gt; and child pipelines&lt;/td&gt;
&lt;td&gt;Blocks/jobs; test reports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;td&gt;Actions cache&lt;/td&gt;
&lt;td&gt;Dependency and Docker layer caching&lt;/td&gt;
&lt;td&gt;Cache and artifacts&lt;/td&gt;
&lt;td&gt;Cache and artifacts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH debugging&lt;/td&gt;
&lt;td&gt;No native SSH into a GitHub-hosted job&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Runner-dependent&lt;/td&gt;
&lt;td&gt;Cloud only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-hosted execution&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅; Cloud agents plus CE/EE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security scanning&lt;/td&gt;
&lt;td&gt;GitHub-native and marketplace; plan-dependent&lt;/td&gt;
&lt;td&gt;Orbs/integrations; plan-dependent&lt;/td&gt;
&lt;td&gt;GitLab-maintained scanners; tier-dependent&lt;/td&gt;
&lt;td&gt;Integrations; edition-dependent controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container registry&lt;/td&gt;
&lt;td&gt;GHCR&lt;/td&gt;
&lt;td&gt;No built-in registry&lt;/td&gt;
&lt;td&gt;GitLab Container Registry&lt;/td&gt;
&lt;td&gt;No built-in registry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment approvals&lt;/td&gt;
&lt;td&gt;Environments&lt;/td&gt;
&lt;td&gt;Approval jobs&lt;/td&gt;
&lt;td&gt;Environments/approvals&lt;/td&gt;
&lt;td&gt;Cloud/EE promotions; not CE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OIDC&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Cloud/EE; not CE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent context&lt;/td&gt;
&lt;td&gt;Copilot cloud agent uses Actions-powered environments&lt;/td&gt;
&lt;td&gt;Hosted and CLI MCP&lt;/td&gt;
&lt;td&gt;Duo Agent Platform&lt;/td&gt;
&lt;td&gt;Support-enabled MCP; writes separately gated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entry allowance&lt;/td&gt;
&lt;td&gt;2,000 private-repo min/month on GitHub Free&lt;/td&gt;
&lt;td&gt;30,000 credits/month, advertised as 6,000 build min&lt;/td&gt;
&lt;td&gt;400 compute min/month on Free&lt;/td&gt;
&lt;td&gt;$15 credits/month, about 2,000 x64 2-vCPU min&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 GitHub Actions if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your code is on GitHub and native event, permission, and status-check integration matters&lt;/li&gt;
&lt;li&gt;You want a broad marketplace of reusable actions&lt;/li&gt;
&lt;li&gt;You maintain public repositories that can use standard hosted runners at no charge&lt;/li&gt;
&lt;li&gt;You need matrix-based workflows close to issues and pull requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use CircleCI if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Timing-based test splitting or granular resource classes materially improve your workload&lt;/li&gt;
&lt;li&gt;You want SSH debugging into supported failed-build environments&lt;/li&gt;
&lt;li&gt;You need a standalone CI service across supported Git providers&lt;/li&gt;
&lt;li&gt;You are prepared to model credit consumption by executor rather than compare headline minutes alone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use GitLab CI if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your source, merge requests, registry, deployments, and CI/CD already live in GitLab&lt;/li&gt;
&lt;li&gt;You need GitLab-maintained security scanning and have verified which subscription tier includes each control&lt;/li&gt;
&lt;li&gt;You want one DevSecOps platform rather than a separate CI vendor&lt;/li&gt;
&lt;li&gt;Auto DevOps or centralized runner management fits your operating model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Semaphore if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want hosted compute with published per-minute rates and separately priced support&lt;/li&gt;
&lt;li&gt;You want Community Edition or an Enterprise self-hosted control plane and understand the edition gaps&lt;/li&gt;
&lt;li&gt;You are piloting MCP-based CI investigation with support enablement and explicit read/write permission boundaries&lt;/li&gt;
&lt;li&gt;You will validate cost and performance on your own repository before migrating&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Migration Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  From CircleCI to GitHub Actions
&lt;/h3&gt;

&lt;p&gt;CircleCI's &lt;code&gt;config.yml&lt;/code&gt; concepts map directly to GitHub Actions, though the YAML structure differs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# CircleCI (old)&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cimg/node:20.11&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="s"&gt;checkout&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;pnpm install&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;pnpm test&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

&lt;span class="c1"&gt;# GitHub Actions (equivalent)&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&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/checkout@v4&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="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt; &lt;span class="pi"&gt;}&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;pnpm install&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;pnpm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main conceptual shifts: CircleCI &lt;code&gt;orbs&lt;/code&gt; become GitHub Actions &lt;code&gt;uses&lt;/code&gt; references, CircleCI &lt;code&gt;workflows&lt;/code&gt; become GitHub Actions &lt;code&gt;jobs&lt;/code&gt; with &lt;code&gt;needs&lt;/code&gt; dependencies, and CircleCI &lt;code&gt;persist_to_workspace&lt;/code&gt;/&lt;code&gt;attach_workspace&lt;/code&gt; becomes &lt;code&gt;actions/upload-artifact&lt;/code&gt;/&lt;code&gt;actions/download-artifact&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluating a move to Semaphore
&lt;/h3&gt;

&lt;p&gt;Semaphore publishes &lt;a href="https://docs.semaphore.io/getting-started/migration-overview" rel="noopener noreferrer"&gt;provider-specific migration guides&lt;/a&gt;, but migration should still be treated as a proof of concept rather than a one-click conversion. Port one representative pipeline first; hold the commit, dependency graph, cache state, secrets model, runner resources, artifacts, deployment gates, and retry policy constant. Compare wall-clock time, queued time, failure diagnostics, monthly cost, administrative overhead, and the edition-specific controls your production workflow requires before expanding the move.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrating secrets and environment variables
&lt;/h3&gt;

&lt;p&gt;The three YAML examples below show similar repository-level secret references; Semaphore also supports project and organization secrets, with additional secret-access policies limited to Cloud and EE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GitHub Actions — ${{ secrets.TOKEN }}&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;npx wrangler deploy&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;CLOUDFLARE_API_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CF_TOKEN }}&lt;/span&gt;

&lt;span class="c1"&gt;# CircleCI — $TOKEN from project environment variables&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="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx wrangler deploy&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CLOUDFLARE_API_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CF_TOKEN&lt;/span&gt;

&lt;span class="c1"&gt;# GitLab CI — $TOKEN from CI/CD variables settings&lt;/span&gt;
&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLOUDFLARE_API_TOKEN=$CF_TOKEN npx wrangler deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ecosystem Context in 2026
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt; is the lowest-friction option for many GitHub-hosted projects because checks, permissions, environments, and releases share GitHub's repository model. Its marketplace breadth is useful, but it also increases third-party action review and pinning responsibilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CircleCI&lt;/strong&gt; remains relevant for teams invested in timing-based test splitting, resource-class tuning, SSH debugging, and support for multiple source hosts. Whether those benefits beat migration and credit costs is repository-specific.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitLab CI&lt;/strong&gt; is most directly comparable as part of the GitLab platform. Source, registry, deployment, security, and agent features can share a permission model, while advanced security, compliance, and Duo capabilities are tier- or usage-gated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semaphore&lt;/strong&gt; is included here only as an unranked fourth shortlist candidate. Its transparent compute rates, CE/EE self-hosting paths, and MCP tools justify evaluation for some teams, but neither vendor outreach nor its vendor-run benchmark determines inclusion, ordering, or the final recommendation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Notes
&lt;/h2&gt;

&lt;p&gt;Official sources checked on &lt;strong&gt;August 11, 2026&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://docs.github.com/en/billing/concepts/product-billing/github-actions" rel="noopener noreferrer"&gt;Actions billing&lt;/a&gt; and &lt;a href="https://docs.github.com/en/copilot/concepts/agents/cloud-agent/about-cloud-agent" rel="noopener noreferrer"&gt;Copilot cloud agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CircleCI: &lt;a href="https://circleci.com/pricing/" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;, &lt;a href="https://circleci.com/docs/guides/optimize/parallelism-faster-jobs/" rel="noopener noreferrer"&gt;test splitting&lt;/a&gt;, &lt;a href="https://circleci.com/docs/guides/execution-managed/ssh-access-jobs/" rel="noopener noreferrer"&gt;SSH reruns&lt;/a&gt;, and &lt;a href="https://circleci.com/product/mcp/" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitLab: &lt;a href="https://about.gitlab.com/pricing/" rel="noopener noreferrer"&gt;pricing and Duo Agent Platform allowances&lt;/a&gt; and &lt;a href="https://docs.gitlab.com/user/application_security/" rel="noopener noreferrer"&gt;application security documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Semaphore: &lt;a href="https://semaphore.io/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;, &lt;a href="https://docs.semaphore.io/getting-started/features" rel="noopener noreferrer"&gt;edition feature matrix&lt;/a&gt;, &lt;a href="https://docs.semaphore.io/getting-started/install" rel="noopener noreferrer"&gt;self-hosted editions&lt;/a&gt;, &lt;a href="https://docs.semaphore.io/using-semaphore/ai/mcp-server" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt;, &lt;a href="https://docs.semaphore.io/getting-started/migration-overview" rel="noopener noreferrer"&gt;migration overview&lt;/a&gt;, and the vendor's &lt;a href="https://semaphore.io/blog/semaphore-ci-cd-benchmark-performance-and-cost-analysis" rel="noopener noreferrer"&gt;CI/CD benchmark&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Methodology and Editorial Independence
&lt;/h2&gt;

&lt;p&gt;PkgPulse checked official GitHub Actions billing, CircleCI pricing and MCP documentation, GitLab pricing and Duo Agent Platform details, and Semaphore pricing, edition matrix, migration, MCP, and benchmark pages on &lt;strong&gt;August 11, 2026&lt;/strong&gt;. Prices, allowances, product names, and feature gates are volatile; re-check the linked first-party pages before making a purchase or migration decision.&lt;/p&gt;

&lt;p&gt;The comparison keeps the existing GitHub Actions vs CircleCI vs GitLab CI search intent and treats Semaphore as an unranked fourth candidate rather than creating a new URL. Vendor claims are attributed, and Semaphore's benchmark is not treated as independent testing. PkgPulse did not accept payment or promise placement, ranking, timing, favorable coverage, or specific link treatment for this refresh. Recommendations are based on reader utility and the evidence available at review time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.pkgpulse.com" rel="noopener noreferrer"&gt;Compare DevOps tooling and CI/CD 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/vercel-vs-netlify-vs-cloudflare-pages-deployment-2026" rel="noopener noreferrer"&gt;Vercel vs Netlify vs Cloudflare Pages&lt;/a&gt;, &lt;a href="https://www.pkgpulse.com/guides/chromatic-vs-percy-vs-applitools-visual-regression-2026" rel="noopener noreferrer"&gt;Chromatic vs Percy vs Applitools&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/github-actions-vs-circleci-vs-gitlab-ci-cicd-platforms-2026" rel="noopener noreferrer"&gt;PkgPulse&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Best Machine Learning Courses 2026</title>
      <dc:creator>Royce</dc:creator>
      <pubDate>Wed, 14 Oct 2026 16:00:33 +0000</pubDate>
      <link>https://dev.to/royce_fabbd83cb268312e928/best-machine-learning-courses-2026-14fp</link>
      <guid>https://dev.to/royce_fabbd83cb268312e928/best-machine-learning-courses-2026-14fp</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.coursefacts.com/guides/best-machine-learning-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;Machine learning education has matured — the early days of ML courses teaching deprecated tools or outdated techniques have mostly passed. The best ML courses in 2026 teach with Python, scikit-learn, TensorFlow, and PyTorch, and address both classical ML and modern deep learning.&lt;/p&gt;

&lt;p&gt;Here are the best machine learning courses in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Picks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Best Course&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best overall (fundamentals)&lt;/td&gt;
&lt;td&gt;Machine Learning Specialization (Andrew Ng, Coursera)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best practical deep learning&lt;/td&gt;
&lt;td&gt;Practical Deep Learning (fast.ai, free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best deep learning depth&lt;/td&gt;
&lt;td&gt;Deep Learning Specialization (Andrew Ng, Coursera)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for applications&lt;/td&gt;
&lt;td&gt;DeepLearning.AI short courses (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best free option&lt;/td&gt;
&lt;td&gt;fast.ai + Kaggle Learn (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for applied ML&lt;/td&gt;
&lt;td&gt;Kaggle competitions + real datasets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The ML Learning Stack in 2026
&lt;/h2&gt;

&lt;p&gt;ML education breaks into distinct levels:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Classical ML:&lt;/strong&gt; Linear/logistic regression, decision trees, random forests, SVMs, clustering. The foundation that still powers most production ML. Andrew Ng's ML Specialization is the gold standard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep Learning:&lt;/strong&gt; Neural networks, CNNs, RNNs, transformers. The basis for modern image recognition, NLP, and generative AI. Andrew Ng's Deep Learning Specialization covers this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Applied AI/LLM:&lt;/strong&gt; Using and building on large language models, fine-tuning, RAG, agents. DeepLearning.AI short courses (free) are the best resources here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production ML / MLOps:&lt;/strong&gt; Feature engineering at scale, model serving, monitoring, retraining pipelines. The Full Stack Deep Learning course covers this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Machine Learning Courses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Machine Learning Specialization — Andrew Ng (&lt;a href="https://www.coursefacts.com/platform/coursera" rel="noopener noreferrer"&gt;Coursera&lt;/a&gt;)
&lt;/h3&gt;

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

&lt;p&gt;The &lt;a href="https://www.coursefacts.com/guides/andrew-ng-ml-course-review-2026" rel="noopener noreferrer"&gt;Andrew Ng ML Specialization&lt;/a&gt; is the most important ML course for learners who want genuine conceptual understanding. Three courses:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Supervised Learning:&lt;/strong&gt; Linear regression, logistic regression, regularization, scikit-learn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Learning Algorithms:&lt;/strong&gt; Neural networks, TensorFlow, decision trees, XGBoost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unsupervised Learning:&lt;/strong&gt; K-means, anomaly detection, recommender systems, RL intro&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What makes it exceptional:&lt;/strong&gt; Ng teaches why algorithms work (gradient descent, cost functions, bias/variance tradeoff) rather than just how to call sklearn. The conceptual depth is unmatched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Basic Python, high school algebra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Software engineers and data analysts who want genuine ML understanding. The standard recommendation for "where do I start with ML?"&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Practical Deep Learning for Coders — fast.ai (Free)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://course.fast.ai" rel="noopener noreferrer"&gt;fast.ai/courses&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; Intermediate (some Python required)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jeremy Howard's fast.ai takes a top-down, application-first approach — the opposite of Andrew Ng's bottom-up mathematical foundation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What fast.ai covers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State-of-the-art image classification, NLP, tabular data&lt;/li&gt;
&lt;li&gt;PyTorch and the fastai library&lt;/li&gt;
&lt;li&gt;Building real applications (image classifier, language model) from lesson 1&lt;/li&gt;
&lt;li&gt;Stable diffusion and generative models&lt;/li&gt;
&lt;li&gt;Ethics in ML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The fast.ai philosophy:&lt;/strong&gt; Get results first, understand why later. This approach suits learners who get bored with theory before they've built something working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers who want to build working ML applications quickly. Many serious ML practitioners recommend both Ng (theory) and fast.ai (application).&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Deep Learning Specialization — Andrew Ng (Coursera)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Duration:&lt;/strong&gt; ~5 months | &lt;strong&gt;Rating:&lt;/strong&gt; 4.9/5 | &lt;strong&gt;Cost:&lt;/strong&gt; Coursera Plus&lt;/p&gt;

&lt;p&gt;The logical continuation of the ML Specialization, focused on neural networks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Neural Networks and Deep Learning&lt;/li&gt;
&lt;li&gt;Improving Deep Neural Networks (hyperparameter tuning, regularization, optimization)&lt;/li&gt;
&lt;li&gt;Structuring ML Projects&lt;/li&gt;
&lt;li&gt;CNNs (computer vision)&lt;/li&gt;
&lt;li&gt;Sequence Models (RNNs, LSTMs, attention, transformers intro)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Learners who want to understand the architecture underlying modern deep learning — the same foundations that power large language models.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Kaggle Learn (Free)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.kaggle.com/learn" rel="noopener noreferrer"&gt;Kaggle Learn&lt;/a&gt; provides free mini-courses on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Pandas and data manipulation&lt;/li&gt;
&lt;li&gt;Machine learning intro (scikit-learn)&lt;/li&gt;
&lt;li&gt;Intermediate ML (missing values, categorical variables, pipelines)&lt;/li&gt;
&lt;li&gt;Feature engineering&lt;/li&gt;
&lt;li&gt;Deep learning&lt;/li&gt;
&lt;li&gt;Computer vision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each mini-course takes 4–8 hours and includes interactive exercises with real datasets. The combination of Kaggle Learn + active Kaggle competition participation is an extremely effective practical ML education.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Learners who want free, interactive ML fundamentals alongside competition practice.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. DeepLearning.AI Short Courses (Free + Paid)
&lt;/h3&gt;

&lt;p&gt;For applied AI and LLM-specific content, DeepLearning.AI's short course catalog is unmatched:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free (1 hour each):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ChatGPT Prompt Engineering for Developers&lt;/li&gt;
&lt;li&gt;Building Systems with the ChatGPT API&lt;/li&gt;
&lt;li&gt;LangChain for LLM Application Development&lt;/li&gt;
&lt;li&gt;How Diffusion Models Work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Paid (~$29 each):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building and Evaluating Advanced RAG&lt;/li&gt;
&lt;li&gt;Fine-Tuning LLMs&lt;/li&gt;
&lt;li&gt;ML for Production (MLOps)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Developers building LLM-powered applications who want current, practical content from practitioners.&lt;/p&gt;




&lt;h2&gt;
  
  
  ML Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving into ML courses:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Required:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python (basic to intermediate — functions, classes, list comprehensions)&lt;/li&gt;
&lt;li&gt;NumPy and pandas basics&lt;/li&gt;
&lt;li&gt;High school algebra (functions, graphs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Helpful:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Statistics (mean, variance, probability distributions)&lt;/li&gt;
&lt;li&gt;Calculus intuition (what a derivative is — not computation)&lt;/li&gt;
&lt;li&gt;Linear algebra basics (vectors, matrices — not rigorous)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kaggle Learn covers Python, pandas, and ML introductory material in a self-contained free curriculum if you need to build prerequisites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Classical ML vs. Deep Learning in 2026
&lt;/h2&gt;

&lt;p&gt;A frequent question: should I focus on classical ML (scikit-learn) or deep learning (PyTorch/TensorFlow)?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Classical ML still dominates production:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most business ML (churn prediction, fraud detection, recommendation, pricing) uses gradient boosting (XGBoost, LightGBM)&lt;/li&gt;
&lt;li&gt;These models are faster to train, more interpretable, and often outperform neural networks on tabular data&lt;/li&gt;
&lt;li&gt;Andrew Ng's ML Specialization covers this well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deep learning is required for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Computer vision (image classification, detection)&lt;/li&gt;
&lt;li&gt;NLP (any text-related ML)&lt;/li&gt;
&lt;li&gt;Generative AI (foundation models, diffusion)&lt;/li&gt;
&lt;li&gt;Time series at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Learn classical ML first (Andrew Ng's ML Specialization), then add deep learning (Deep Learning Specialization or fast.ai). Don't skip classical ML to start with neural networks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kaggle: The Essential Supplement
&lt;/h2&gt;

&lt;p&gt;No course prepares you for real ML work as effectively as competing on Kaggle. Competitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide real, messy datasets with business context&lt;/li&gt;
&lt;li&gt;Require you to solve problems without step-by-step guidance&lt;/li&gt;
&lt;li&gt;Develop feature engineering and model selection intuition&lt;/li&gt;
&lt;li&gt;Create public portfolio work (your Kaggle notebooks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Getting started on Kaggle:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Complete Kaggle Learn basics&lt;/li&gt;
&lt;li&gt;Enter a Getting Started competition (Titanic or House Prices)&lt;/li&gt;
&lt;li&gt;Analyze top-scoring public notebooks to learn techniques&lt;/li&gt;
&lt;li&gt;Enter monthly competitions with real prizes&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Learning Path: ML Engineer (12 Months)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Months 1–2:&lt;/strong&gt; Andrew Ng ML Specialization (fundamentals)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Months 3–4:&lt;/strong&gt; Deep Learning Specialization (neural networks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month 5:&lt;/strong&gt; fast.ai Practical Deep Learning (applied perspective)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Months 6–7:&lt;/strong&gt; Kaggle competitions — 2–3 complete competition entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Months 8–9:&lt;/strong&gt; DeepLearning.AI applied courses (RAG, agents, deployment)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Months 10–12:&lt;/strong&gt; Portfolio project + MLOps (full pipeline from data to production)&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;&lt;strong&gt;For ML foundations:&lt;/strong&gt; Andrew Ng's Machine Learning Specialization is the best course for understanding why ML works. Start here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For applied deep learning:&lt;/strong&gt; fast.ai is the best complement — it teaches building working models quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For free learning:&lt;/strong&gt; Kaggle Learn + fast.ai + DeepLearning.AI's free short courses provide a complete path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest truth:&lt;/strong&gt; Courses teach you concepts. Kaggle competitions teach you to actually do ML. Do both.&lt;/p&gt;

&lt;p&gt;See our &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 look at the foundational course, or our &lt;a href="https://www.coursefacts.com/guides/best-data-science-courses-2026" rel="noopener noreferrer"&gt;best data science courses guide&lt;/a&gt; for the broader data science learning landscape.&lt;/p&gt;




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

</description>
    </item>
    <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>
  </channel>
</rss>
