Cleaning up nuget repostories - Sonatype Nexus Repository - Sonatype Community
Cleaning up nuget repostories
post by Orion_Poplawski on Nov 12, 2025
I would like to cleanup our nuget repositories to only have the latest version of each package. Is there a simple way to do that?
post by jzora on Nov 12, 2025
Hi, Orion! That’s a good question; the answer is “kind of,” and it depends on your use case.
What’s the goal here? Are you trying to free up space, get developers to use certain packages, reduce risk, etc. etc.?
post by Orion_Poplawski on Nov 12, 2025
Reduce disk space - we only install the latest version of packages so we don’t need the old versions.
post by jzora on Nov 12, 2025
Okay, thank you! There’s not an easy way to eliminate everything but the latest version in a nuget repository. If disk space is your concern, adjust your cleanup policies to be more aggressive. I’m sure you know there’s a huge variance in the release cadence of nuget packages, so I can’t recommend a default value, but since the issue is disk space, go low!
Preview the results with the button at the bottom of the “Create Cleanup Policy” page to get a sense for how effective your policy will be, and be sure you have Cleanup Tasks and Compact Blob Store Tasks to actually reclaim the disk space.
post by Orion_Poplawski on Nov 14, 2025
I find the included cleanup options limited for what I’m interested in. I ended up with the following script run as a jenkins task to handle the cleanup:
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]
$ProdRepoApiKey,
[Parameter(Mandatory)]
[PSCredential]$Credential
)
# List of Nexus server URLs
$servers = @(
"https://repo1.example.com:8443",
"https://repo2.example.com"
)
# Helper function to get NuGet repositories
function Get-NuGetRepositories {
param ($ServerUrl)
$uri = "$ServerUrl/service/rest/v1/repositories"
$response = Invoke-RestMethod -Uri $uri -Headers @{Accept = "application/json"} -Authentication Basic -Credential $Credential -Verbose:$false
return $response | Where-Object { $_.format -eq "nuget" -and $_.type -ne "group" } | Select-Object -ExpandProperty name
}
# Helper function to get components
function Get-Components {
param ($ServerUrl, $Repository, $Token)
$uri = "$ServerUrl/service/rest/v1/components?repository=$Repository"
if ($Token) {
$uri += "&continuationToken=$Token"
}
return Invoke-RestMethod -Uri $uri -Headers @{Accept = "application/json"} -Authentication Basic -Credential $Credential -Verbose:$false
}
# Helper function to delete a component
function Delete-Component {
param ($ServerUrl, $Component)
$uri = "$ServerUrl/service/rest/v1/components/$($Component.id)"
$response = Invoke-WebRequest -Uri $uri -Method Delete -Authentication Basic -Credential $Credential -ErrorAction SilentlyContinue -Verbose:$false -SkipHTTPErrorCheck
#$response = @{'StatusCode' = 204}
if ($response.StatusCode -eq 204) {
Write-Verbose "Deleted $($Component.name)/$($Component.version) $($Component.assets) $($Component.assets.Count) component $($Component.id) from $ServerUrl"
} else {
Write-Warning "Failed to delete $($Component.name)/$($Component.version) $($Component.id) from ${ServerUrl}: $($response.StatusCode)"
}
}
# Main logic
foreach ($serverUrl in $servers) {
try {
$repos = Get-NuGetRepositories -ServerUrl $serverUrl
foreach ($repo in $repos) {
Write-Verbose "Processing repository '$repo' on $serverUrl"
$token = $null
do {
$result = Get-Components -ServerUrl $serverUrl -Repository $repo -Token $token
foreach ($component in $result.items) {
$assets = $component.assets
if ($assets.Count -eq 0) { continue }
$allNotLatest = $true
foreach ($asset in $assets) {
# Do not delete if filesize is 0 - chocolatey repo has stub entries
if ($asset.nuget -and $asset.nuget.is_latest_version -eq $true -or $asset.fileSize -eq 0) {
$allNotLatest = $false
break
}
}
if ($allNotLatest) {
Delete-Component -ServerUrl $serverUrl -Component $component
}
}
$token = $result.continuationToken
} while ($token)
}
} catch {
Write-Error "Error processing ${serverUrl}: $_"
}
}