Asynchronous programming in .NET and C# is omnipresent these days.

To understand the purpose of ValueTask we first have to understand Stack vs Heap memory.

Task<Post[]> LoadPostsAsync()
{
    return await _dbContext.Posts.ToArrayAsync();
}

A Task is a class and thus will be allocated on the Heap memory.

But what if we already have the Posts cached in memory and do not have to access the DB again? Here comes ValueTask into play!

A ValueTask is a struct and thus will be allocated on the Stack memory.

ValueTask<Post[]> LoadPostsAsync()
{
    var posts = _memoryCache.Get<Post[]>("Posts");

    if (posts is not null)
    {
        // Synchronously return the posts from memory
        return posts;
    }

    // Asynchronously return the posts from database
    return await _dbContext.Posts.ToArrayAsync();
}

That's it! We saved a Task allocation on the Heap memory when the posts are already available in the cache.