GitHub Actions supports sharing data between jobs in a workflow using artifacts. This is useful, but storage is limited unless you pay for more. If you use too much storage, you may receive a notification like this:
You've used 75% of included services for GitHub Storage (GitHub Actions and Packages)
One way to reclaim storage is to delete old artifacts. You can do this manually, but it becomes tedious across many workflow runs. A better approach is to write a script that deletes artifacts automatically using the GitHub API.
Let's create a new .NET console application.
Shell
dotnet new console
C#
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
// https://github.com/settings/tokens/new
const string GithubToken = "ghp_***";
// TODO List the project that contains artifacts
var projects = new[]
{
"meziantou/project1",
"meziantou/project2",
"meziantou/project3",
};
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", GithubToken);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "ArtifactsCleaner/1.0");
httpClient.BaseAddress = new Uri("https://api.github.com");
foreach (var project in projects)
{
// Get all project's artifacts
var artifacts = new List<Artifact>();
var pageIndex = 1;
var pageSize = 100;
Artifacts page;
do
{
var url = $"/repos/{project}/actions/artifacts?per_page={pageSize}&page={pageIndex}";
page = await httpClient.GetFromJsonAsync<Artifacts>(url);
artifacts.AddRange(page.Items);
pageIndex++;
} while (page.Items.Length >= pageSize);
// Delete artifacts older than 1 day
foreach (var item in artifacts)
{
if (!item.Expired && item.CreatedAt < DateTime.UtcNow.AddDays(-1))
{
var deleteUrl = $"repos/{project}/actions/artifacts/{item.Id}";
try
{
Console.WriteLine(deleteUrl);
await httpClient.DeleteAsync(deleteUrl);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
record Artifacts([property: JsonPropertyName("artifacts")] Artifact[] Items);
record Artifact(
int Id,
bool Expired,
[property: JsonPropertyName("created_at")] DateTime CreatedAt);
After cleaning up existing artifacts, update your workflow to automatically expire new ones by setting the retention-days property:
YAML
- uses: actions/upload-artifact@v2
with:
name: demo
path: '**/*.txt'
retention-days: 3
You can also configure this value in the project or organization settings:

#Additional resources
Do you have a question or a suggestion about this post? Contact me!