ActionsToolkit.Artifact 1.0.0

dotnet add package ActionsToolkit.Artifact --version 1.0.0
                    
NuGet\Install-Package ActionsToolkit.Artifact -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ActionsToolkit.Artifact" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ActionsToolkit.Artifact" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ActionsToolkit.Artifact" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ActionsToolkit.Artifact --version 1.0.0
                    
#r "nuget: ActionsToolkit.Artifact, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ActionsToolkit.Artifact@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ActionsToolkit.Artifact&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ActionsToolkit.Artifact&version=1.0.0
                    
Install as a Cake Tool

ActionsToolkit.Artifact

NuGet

An unofficial .NET SDK for GitHub Actions workflows, providing a port of the @actions/artifact JavaScript package. Use it from a custom action (or a workflow-driven .NET process running on a GitHub Actions runner) to upload, list, get, download, and delete workflow run artifacts.

Install

<PackageReference Include="ActionsToolkit.Artifact" Version="[Version]" />

Or use the dotnet add package .NET CLI command:

dotnet add package ActionsToolkit.Artifact

Get the IArtifactClient instance

Register the services with an IServiceCollection instance by calling AddGitHubActionsArtifact(), and consuming code can require the IArtifactClient via constructor dependency injection.

using ActionsToolkit.Artifact;
using ActionsToolkit.Artifact.Extensions;
using Microsoft.Extensions.DependencyInjection;

using var provider = new ServiceCollection()
    .AddGitHubActionsArtifact()
    .BuildServiceProvider();

var client = provider.GetRequiredService<IArtifactClient>();

AddGitHubActionsArtifact() reads ACTIONS_RESULTS_URL, ACTIONS_RUNTIME_TOKEN, GITHUB_TOKEN, and GITHUB_API_URL (set automatically by the runner) at the time each HttpClient is materialized; you don't need to configure them explicitly.

Basic usage

The client mirrors the JavaScript ArtifactClient surface with five idiomatic .NET methods returning ValueTask<T>.

Upload an artifact

string[] files = { "logs/build.log", "logs/test.trx" };

UploadArtifactResponse response = await client.UploadArtifactAsync(
    name: "build-logs",
    files: files,
    rootDirectory: "logs");

Console.WriteLine($"Uploaded artifact {response.Id} ({response.Size} bytes, digest {response.Digest})");

UploadArtifactOptions controls retention (RetentionDays) and ZIP compression (CompressionLevel, 0-9 mapped onto .NET CompressionLevel values: 0 → NoCompression, 1-3 → Fastest, 4-6 → Optimal, 7-9 → SmallestSize).

List artifacts in a run

ListArtifactsResponse list = await client.ListArtifactsAsync();
foreach (var artifact in list.Artifacts)
{
    Console.WriteLine($"{artifact.Id}: {artifact.Name} ({artifact.Size} bytes)");
}

ListArtifactsOptions.LatestOnly filters out re-uploads of an artifact with the same name, keeping the most recent only. FindOptions.FindBy lets you target a different repository / run / token combination.

Get a single artifact by name

GetArtifactResponse result = await client.GetArtifactAsync("build-logs");
Console.WriteLine($"Found {result.Artifact.Id} created {result.Artifact.CreatedAt:o}");

Download an artifact

DownloadArtifactResponse download = await client.DownloadArtifactAsync(
    artifactId: result.Artifact.Id,
    options: new DownloadArtifactOptions { Path = "./extracted" });

Console.WriteLine($"Extracted to {download.DownloadPath}");

DownloadArtifactOptions.SkipDecompress = true keeps the raw .zip on disk instead of expanding it.

Delete an artifact

DeleteArtifactResponse deleted = await client.DeleteArtifactAsync("build-logs");
Console.WriteLine($"Deleted artifact {deleted.Id}");

Architecture

The package decomposes the artifact flows into injectable seams:

  • IArtifactClient — the public façade. The DI default (DefaultArtifactClient) routes upload through the Twirp pipeline and list/get/download/delete through the public REST API at https://api.github.com/.
  • IArtifactService (internal) — Twirp transport. Issues POST /twirp/github.actions.results.api.v1.ArtifactService/<Method> requests with the runtime token bearer.
  • IPublicArtifactsApi (internal) — Public REST transport for the list / get / download / delete operations, using GITHUB_TOKEN.
  • IBackendIdsProvider (internal) — reads ACTIONS_RUNTIME_TOKEN and parses the JWT scp claim once. JWT parsing is hand-rolled with JsonDocument + Base64Url to keep the package free of Microsoft.IdentityModel.* reflection paths and AOT-clean.

The package registers three named HttpClient instances:

Name Purpose
ActionsToolkit.Artifact Twirp transport (bearer auth from ACTIONS_RUNTIME_TOKEN).
ActionsToolkit.Artifact.PublicApi REST API at https://api.github.com/, no auto-redirect.
ActionsToolkit.Artifact.Blob Bare client for blob upload/download via signed URLs (no auth).

AllowAutoRedirect=false on the public REST client lets DownloadArtifactAsync extract the signed blob URL from the 302 Location header before sending the GitHub bearer token to Azure.

GHES support

The list / get / download / delete operations require GitHub.com (or *.ghe.com); they throw GhesNotSupportedException on a GHES host. Uploads always go through the Twirp endpoint and continue to work on GHES.

Errors

Exception Thrown when
InvalidArtifactNameException name is null/empty or contains a forbidden character.
InvalidArtifactTokenException ACTIONS_RUNTIME_TOKEN is missing or not a parseable Actions JWT.
FilesNotFoundException None of the supplied upload paths exist on disk.
ArtifactUploadException The Twirp create / blob PUT / Twirp finalize step failed.
ArtifactNotFoundException The requested artifact does not exist (list / get / delete).
ArtifactNetworkException A network call to the public REST API or blob storage failed.
ArtifactUsageException Required runner environment variables (e.g., GITHUB_TOKEN) are missing.
InvalidArtifactResponseException The Twirp / REST server returned a malformed response body.
GhesNotSupportedException A list / get / download / delete call was made on a GHES host.

Attribution

Based on the original Node.js @actions/artifact package by GitHub. The original C# upload skeleton was contributed by @js6pak in #4 and is preserved as the first commit on the adoption branch.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 80 5/5/2026
1.0.0-rc.1 44 5/5/2026