'use client'; import { forwardRef, ReactElement, ReactNode, useCallback, useEffect, useRef, useState, } from 'react'; import { ButtonLink, SectionHeading, Strong, TextLink, } from '@nx/nx-dev/ui-common'; import { cx } from '@nx/nx-dev/ui-primitives'; import { AnimatedCurvedBeam } from '@nx/nx-dev/ui-animations'; import { CircleStackIcon, ServerIcon, XMarkIcon, } from '@heroicons/react/24/outline'; import { AmazonS3Icon, AzureDevOpsIcon, GoogleCloudIcon, MinIOIcon, NxIcon, } from '@nx/nx-dev/ui-icons'; import Link from 'next/link'; import { AnimatePresence, motion } from 'framer-motion'; export function PowerpackFeatures(): ReactElement { return (

Looking for self-hosted caching? It is now free for everyone 

{/*
Self-hosted cache storage

Use Amazon S3, MinIO,{' '} GCP, Azure or a{' '} shared network drive as your remote cache storage, offering a flexible, self-managed solution for faster builds. Nx Powerpack self-hosted cache storage is{' '} free for small teams .

Learn about self-hosted cache storage
*/}
Codeowners for monorepos

Common VCS providers require folder-based ownership definitions. Now, define and manage ownership where it matters— at the project level.

Bridge the gap by{' '} automatically tracking changes and syncing ownership data {' '} with GitHub, GitLab, or Bitbucket-specific CODEOWNERS files. This ensures clear responsibilities and enables efficient collaboration across large-scale projects.

Learn more about codeowners
Workspace conformance

Define and run conformance rules throughout your workspace , leverage built-in rules or{' '} create your own to ensure compliance with organizational standards.

With Nx Enterprise, you can{' '} upload your custom rules to your Nx Cloud organization {' '} and automatically enforce them across multiple repositories and workspaces, regardless of your tech stack.

Learn how to use conformance rules
trust & secure illustration trust & secure illustration
Trustworthy and secure

Nx Powerpack is reliably maintained by the Nx team. Nx (the company) adheres to strict security and data-handling standards, including compliance with SOC 2 (Type 1 and Type 2).

See our Trust Report
Faster procurement, simpler licensing

A simple{' '} licensing model that reduces red tape and speeds up procurement processes . Your teams can get started quickly without lengthy negotiations, ensuring a faster go-to-market.

Ready to go for Nx Enterprise

Nx Powerpack is included at no extra cost for Nx Enterprise customers , unlocking additional capabilities without needing to manage more tools or onboard a new vendor.{' '} Request a free trial of Nx Enterprise .

); } const Card = forwardRef< HTMLDivElement, { className?: string; children?: ReactNode; onMouseEnter?: () => void; onMouseLeave?: () => void; } >(({ className, children, onMouseEnter, onMouseLeave }, ref) => { return (
{children}
); }); Card.displayName = 'Card'; export function CustomRemoteCacheAnimation(): ReactElement { const awsRef = useRef(null); const azureRef = useRef(null); const containerRef = useRef(null); const gcpRef = useRef(null); const minioRef = useRef(null); const networkDriveRef = useRef(null); const nxRef = useRef(null); const animatedBeamMap: Record = { aws: ( ), azure: ( ), gcp: ( ), minio: ( ), networkDrive: ( ), }; const links = Object.keys(animatedBeamMap); const duration = 6000; const timeout = useRef(); const [selected, setSelected] = useState('aws'); const [autoplay, setAutoplay] = useState(true); const play = useCallback(() => { timeout.current = setTimeout(next, duration); }, [selected]); const next = () => { if (links.length <= 1) return; // No change if there's only one or no items if (selected === null) return setSelected(links[Math.floor(Math.random() * links.length)]); const availableLinks = links.filter((link) => link !== selected); const randomIndex = Math.floor(Math.random() * availableLinks.length); setSelected(availableLinks[randomIndex]); }; useEffect(() => { clearTimeout(timeout.current); if (autoplay) play(); }, [selected, autoplay, play]); return (
{ setAutoplay(false); setSelected('aws'); }} onMouseLeave={() => { setAutoplay(true); setSelected(null); }} className={cx( 'relative transition hover:bg-slate-50 dark:hover:bg-slate-800', { 'bg-slate-50 dark:bg-slate-800': selected === 'aws' } )} > { setAutoplay(false); setSelected('minio'); }} onMouseLeave={() => { setAutoplay(true); setSelected(null); }} className={cx( 'relative transition hover:bg-slate-50 dark:hover:bg-slate-800', { 'bg-slate-50 dark:bg-slate-800': selected === 'minio' } )} > { setAutoplay(false); setSelected('networkDrive'); }} onMouseLeave={() => { setAutoplay(true); setSelected(null); }} className={cx( 'relative transition hover:bg-slate-50 dark:hover:bg-slate-800', { 'bg-slate-50 dark:bg-slate-800': selected === 'networkDrive' } )} > { setAutoplay(false); setSelected('gcp'); }} onMouseLeave={() => { setAutoplay(true); setSelected(null); }} className={cx( 'relative transition hover:bg-slate-50 dark:hover:bg-slate-800', { 'bg-slate-50 dark:bg-slate-800': selected === 'gcp' } )} > { setAutoplay(false); setSelected('azure'); }} onMouseLeave={() => { setAutoplay(true); setSelected(null); }} className={cx( 'relative transition hover:bg-slate-50 dark:hover:bg-slate-800', { 'bg-slate-50 dark:bg-slate-800': selected === 'azure' } )} >
{selected ? ( {animatedBeamMap[selected]} ) : null}
); }