Fiber UI LogoFiberUI

useHardwareConcurrency

Get the number of logical CPU cores to auto-scale thread pools or lower graphics settings for low-end devices.

Installation

npx shadcn@latest add https://r.fiberui.com/r/hooks/use-hardware-concurrency.json

A React hook that returns the number of logical processors available to run threads on the user's computer. This is useful for scaling worker pools, deciding on graphics fidelity, or adjusting application workload based on device capabilities.

Fallback Value

Returns 1 if the navigator.hardwareConcurrency property is not supported by the browser or during Server-Side Rendering (SSR).

Features

  • Device Scaling - Adjust your app's performance based on available cores
  • Type Safe - Fully typed for TypeScript
  • SSR Safe - Returns a safe fallback during server-side rendering

Basic Usage

Logical Cores Detected

Logical Cores Detected

Your device's processing capacity

1
"use client";

import { useHardwareConcurrency } from "@repo/hooks/performance/use-hardware-concurrency";
import { Card } from "@repo/ui/components/card";
import { Cpu } from "lucide-react";

export function Example1() {
    const cores = useHardwareConcurrency();

    return (
        <Card className="mx-auto flex max-w-sm flex-col items-center justify-center gap-4 p-8">
            <div className="bg-primary/10 text-primary flex items-center justify-center rounded-full p-4">
                <Cpu className="h-12 w-12" />
            </div>

            <div className="text-center">
                <h3 className="text-xl font-bold">Logical Cores Detected</h3>
                <p className="text-muted-foreground mt-1 text-sm">
                    Your device's processing capacity
                </p>
            </div>

            <div className="text-primary text-6xl font-black tabular-nums tracking-tighter">
                {cores}
            </div>
        </Card>
    );
}

Auto-Tuning Quality

Auto-Tuning Quality

Device features adjusted based on 1 logical core.

Applied Setting: Quality
Texture Resolution4096px
Background Tasks4 Threads

"use client";

import { useHardwareConcurrency } from "@repo/hooks/performance/use-hardware-concurrency";
import { useState, useEffect } from "react";
import { Card } from "@repo/ui/components/card";

const Progress = ({
    value,
    className,
}: {
    value: number;
    className: string;
}) => (
    <div className={`bg-secondary overflow-hidden rounded-full ${className}`}>
        <div
            className="bg-primary h-full transition-all duration-300"
            style={{ width: `${value}%` }}
        />
    </div>
);

export function Example2() {
    const cores = useHardwareConcurrency();
    const [quality, setQuality] = useState("");
    const [details, setDetails] = useState("");

    useEffect(() => {
        // Automatically determine graphics or app feature quality based on cores
        if (cores >= 8) {
            setQuality("High");
            setDetails(
                "All animations, high-res textures, and background processing enabled.",
            );
        } else if (cores >= 4) {
            setQuality("Medium");
            setDetails(
                "Standard animations, optimized textures, balanced processing.",
            );
        } else {
            setQuality("Low");
            setDetails(
                "Reduced animations, low-res textures, strictly essential processing.",
            );
        }
    }, [cores]);

    return (
        <div className="mx-auto flex w-full max-w-md flex-col gap-6">
            <div className="text-center">
                <h3 className="text-lg font-medium">Auto-Tuning Quality</h3>
                <p className="text-muted-foreground text-sm">
                    Device features adjusted based on {cores} logical{" "}
                    {cores === 1 ? "core" : "cores"}.
                </p>
            </div>

            <Card className="flex flex-col gap-4 p-6">
                <div className="flex items-center justify-between">
                    <span className="font-medium">Applied Setting:</span>
                    <span
                        className={`rounded-md px-2 py-1 text-sm font-bold ${
                            quality === "High"
                                ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400"
                                : quality === "Medium"
                                  ? "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"
                                  : "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400"
                        }`}
                    >
                        {quality} Quality
                    </span>
                </div>

                <div className="space-y-4">
                    <div className="space-y-1">
                        <div className="flex justify-between text-sm">
                            <span>Texture Resolution</span>
                            <span>
                                {quality === "Low"
                                    ? "512px"
                                    : quality === "Medium"
                                      ? "1024px"
                                      : "4096px"}
                            </span>
                        </div>
                        <Progress
                            value={
                                quality === "Low"
                                    ? 33
                                    : quality === "Medium"
                                      ? 66
                                      : 100
                            }
                            className="h-2"
                        />
                    </div>

                    <div className="space-y-1">
                        <div className="flex justify-between text-sm">
                            <span>Background Tasks</span>
                            <span>
                                {quality === "Low"
                                    ? "1 Thread"
                                    : quality === "Medium"
                                      ? "2 Threads"
                                      : "4 Threads"}
                            </span>
                        </div>
                        <Progress
                            value={
                                quality === "Low"
                                    ? 25
                                    : quality === "Medium"
                                      ? 50
                                      : 100
                            }
                            className="h-2"
                        />
                    </div>
                </div>

                <p className="text-muted-foreground mt-2 border-t pt-4 text-xs">
                    {details}
                </p>
            </Card>
        </div>
    );
}

Auto-Scaled Thread Pool

Auto-Scaled Thread Pool

Simulating a background worker pool scaled to max 1 background threads.

"use client";

import { useHardwareConcurrency } from "@repo/hooks/performance/use-hardware-concurrency";
import { useState, useEffect } from "react";
import { Button } from "@repo/ui/components/button";
import { Loader2 } from "lucide-react";

export function Example3() {
    const cores = useHardwareConcurrency();
    const [workers, setWorkers] = useState<{ id: number; status: string }[]>(
        [],
    );
    const [isSimulating, setIsSimulating] = useState(false);

    useEffect(() => {
        // Initialize pool based on available cores (leaving 1 for main thread if possible)
        const poolSize = Math.max(1, cores - 1);
        const initialPool = Array.from({ length: poolSize }).map((_, i) => ({
            id: i + 1,
            status: "Idle",
        }));
        setWorkers(initialPool);
    }, [cores]);

    const simulateWork = () => {
        setIsSimulating(true);

        // Randomly assign work to the available scaled threads
        const updatedWorkers = workers.map((w) => ({
            ...w,
            status: "Working...",
        }));

        setWorkers(updatedWorkers);

        // Simulate finishing work at random times
        updatedWorkers.forEach((w) => {
            setTimeout(
                () => {
                    setWorkers((current) =>
                        current.map((cw) =>
                            cw.id === w.id ? { ...cw, status: "Done" } : cw,
                        ),
                    );
                },
                1000 + Math.random() * 2000,
            );
        });

        // Reset overall simulation state
        setTimeout(() => setIsSimulating(false), 3500);
    };

    return (
        <div className="mx-auto flex w-full max-w-lg flex-col gap-6">
            <div className="text-center">
                <h3 className="text-lg font-medium">Auto-Scaled Thread Pool</h3>
                <p className="text-muted-foreground text-sm">
                    Simulating a background worker pool scaled to max{" "}
                    {Math.max(1, cores - 1)} background threads.
                </p>
            </div>

            <div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
                {workers.map((worker) => (
                    <div
                        key={worker.id}
                        className={`flex flex-col items-center justify-center rounded-xl border p-3 text-sm transition-all duration-500 ${
                            worker.status === "Working..."
                                ? "border-primary/50 bg-primary/10 text-primary"
                                : worker.status === "Done"
                                  ? "border-green-500/50 bg-green-500/10 text-green-600 dark:text-green-400"
                                  : "border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900/50"
                        }`}
                    >
                        <span className="mb-1 font-bold">
                            Worker {worker.id}
                        </span>
                        <div className="flex items-center gap-2">
                            {worker.status === "Working..." && (
                                <Loader2 className="h-3 w-3 animate-spin" />
                            )}
                            <span className="text-xs">{worker.status}</span>
                        </div>
                    </div>
                ))}
            </div>

            <Button
                onClick={simulateWork}
                isDisabled={isSimulating}
                className="w-full self-center sm:w-auto"
            >
                {isSimulating
                    ? "Processing Dataset..."
                    : "Start Heavy Processing"}
            </Button>
        </div>
    );
}

Dynamic Layout Scaling

Dynamic Layout Scaling

Rendering complexity (6 nodes across 2 columns) adjusted for 1 cores.

Node1
Node2
Node3
Node4
Node5
Node6
Devices with fewer cores will render a smaller, simpler grid structure to maintain 60 FPS, while powerful workstations will render denser data visualization.
"use client";

import { useHardwareConcurrency } from "@repo/hooks/performance/use-hardware-concurrency";
import { Card } from "@repo/ui/components/card";

export function Example4() {
    const cores = useHardwareConcurrency();

    // Determine grid columns dynamically based on cores
    const columns = cores >= 16 ? 8 : cores >= 8 ? 6 : cores >= 4 ? 4 : 2;
    // Generate items based on dynamic columns
    const items = Array.from({ length: columns * 3 });

    return (
        <div className="mx-auto flex w-full max-w-2xl flex-col gap-6">
            <div className="text-center">
                <h3 className="text-lg font-medium">Dynamic Layout Scaling</h3>
                <p className="text-muted-foreground text-sm">
                    Rendering complexity ({items.length} nodes across {columns}{" "}
                    columns) adjusted for {cores} cores.
                </p>
            </div>

            <div
                className="grid gap-2"
                style={{
                    gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
                }}
            >
                {items.map((_, i) => (
                    <Card
                        key={i}
                        className="flex aspect-square flex-col items-center justify-center bg-zinc-50 p-2 text-xs transition-colors hover:bg-zinc-100 dark:bg-zinc-900/50 dark:hover:bg-zinc-800"
                    >
                        <span className="font-mono opacity-50">Node</span>
                        <span className="font-bold">{i + 1}</span>
                    </Card>
                ))}
            </div>

            <div className="text-muted-foreground bg-muted/50 rounded-lg p-4 text-center text-xs">
                Devices with fewer cores will render a smaller, simpler grid
                structure to maintain 60 FPS, while powerful workstations will
                render denser data visualization.
            </div>
        </div>
    );
}

API Reference

Hook Signature

function useHardwareConcurrency(): number;

Return Value

Returns a number representing the number of logical CPU cores available on the user's device (e.g., 4, 8, 16).


Hook Source Code

import { useState, useEffect } from "react";

/**
 * Get the number of logical CPU cores (navigator.hardwareConcurrency).
 * Useful for auto-scaling thread pools or adjusting graphics settings.
 * Returns a fallback of 1 if not supported or during SSR.
 */
export function useHardwareConcurrency() {
    const [concurrency, setConcurrency] = useState<number>(1);

    useEffect(() => {
        if (
            typeof navigator !== "undefined" &&
            "hardwareConcurrency" in navigator
        ) {
            setConcurrency(navigator.hardwareConcurrency);
        }
    }, []);

    return concurrency;
}