Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
158110 stories
·
33 followers

Anthropic’s Opus 5 is almost Fable 5

1 Share

Anthropic launched Opus 5 on Friday, the latest version of what used to be the company’s flagship model (before the launch of Fable 5).

Opus 5, Anthropic says, comes close to the performance of Fable 5 in many domains — all at half the price of Fable 5, with the token cost remaining $5/$25 per million input/output tokens, unchanged from Opus 4.8. Unlike Fable 5, users don’t have to opt into a 30-day data retention policy to use Opus 5. It’s now the default model for Claude Max subscribers (and the best model Claude Pro subscribers can access).

Almost Fable 5

Unsurprisingly, Opus 5 is Anthropic’s most capable Opus model yet, and the company stresses that it can also autonomously perform work for much longer than before, checking its own work and recovering from errors.

Fable 5, though, remains the model to go to for “your most ambitious work” and for projects that need days-long autonomy, Anthropic says. Opus 5, meanwhile, is what Anthropic describes as “designed to be used every day.”

It’s probably this ability to work on a project for a very long time that still sets Fable 5 apart, because on virtually every benchmark Anthropic has shared so far, Opus 5 actually outperforms Fable 5.

That leaves Sonnet 5, which launched only a few weeks ago, in a bit of an awkward position between the cheaper, faster but far less capable Haiku 4.5, and the more capable but expensive Opus and Fable family. Sonnet 5, after all, was previously positioned as the “most efficient for everyday tasks.”

Opus 5 benchmarks

The new Opus model is especially strong when it comes to doing knowledge work and improves on Opus 4.8’s coding abilities. It scores 1861 on the GDPval-AA v2 knowledge work benchmark, ahead of Fable 5 (1747), GPT-5.6 Sol (1736), and Opus 4.8 (1593).

It’s also the top model on Zapier’s AutomationBench, which measures AI agents on end-to-end business workflows (and where Google’s new Gemini 3.6 Flash spent a very short time at the top earlier this week). Anthropic says Opus 5’s pass rate there is double the next-best model’s at the same cost per task, and that even at its lowest effort setting, the model passes more tasks than any other.

BenchmarkOpus 5Fable 5Opus 4.8GPT-5.6 Sol
Agentic terminal coding
Frontier-Bench v0.1
43.3%33.7%18.7%37.5%
Knowledge work
GDPval-AA v2
1861174715931736
Agentic search
BrowseComp
90.8%87.4%84.3%90.4%
Multidisciplinary
reasoning

Humanity’s Last Exam
56.3%
no tools

64.7%
with tools
56.5%
no tools

63.9%
with tools
49.8%
no tools

57.9%
with tools


Computer use
OSWorld 2.0
70.6%66.1%55.7%62.6%
Agentic coding
DeepSWE v1.1
68.8%69.7%59.0%72.7%
Agentic coding
FrontierCode v1.1, Main
53.4%53.5%46.5%47.5%
Business workflows
AutomationBench
26.0%17.4%17.0%18.1%
Legal
Legal Agent Benchmark, Held-out
11.7%13.3%10.4%2.5%
Health
HealthBench Professional
59.8%Mythos 5
66.0%
57.4%60.5%
Biology
BioMysteryBench
49.4%
hard

90.1%
human solved
46.5%
hard

Mythos 5
89.0%
human solved
42.4%
hard

88.5%
human solved


Credit: Anthropic

Anthropic also says Opus 5 is its best and most cost-effective model so far on DeepSearchQA and Humanity’s Last Exam (with tools), where it even edges out Fable 5 (64.7 percent vs. 63.9 percent). Without giving the models access to tools, Fable 5 stays ahead.

Fable 5 does keep its lead in a few places, though, among them Anthropic’s held-out legal agent benchmark and DeepSWE, while Mythos 5 remains the company’s strongest model on health benchmarks.

As for coding, Anthropic says that on CursorBench 3.2, Opus 5 beats every other model on performance-per-cost at the high, extra high, and max settings; at max effort, the company says, the model lands within 0.5 percent of Fable 5’s peak score at half the cost per task.

In prepared remarks released by Anthropic, Cursor co-founder Sualeh Asif says, “Claude Opus 5 delivers near Fable 5 intelligence at Opus speed and cost. On CursorBench it’s just under Fable 5 and has many of the same behaviors. We are excited to see how developers use it in Cursor.”

As before, users across Anthropic’s products can choose between low, medium, high, extra high, and max settings with their respective boosts in intelligence (and token usage).

Opus 5 safety

Anthropic also calls Opus 5 its most aligned model to date, based on its automated behavioral audits, and, together with Fable 5, the least susceptible to being tricked into misuse.

The company says it intentionally didn’t train the model on cybersecurity tasks. Opus 5 nevertheless comes close to Mythos 5 at finding vulnerabilities in open-source code, while remaining far behind at actually exploiting them — which is pretty much where Anthropic wants it to be.

To keep it safely out of any Fable 5-like trouble, Opus 5 ships with a set of safety classifiers that screen requests for a narrow range of cyber tasks, including exploit generation and penetration testing. Because they’re scoped more narrowly than Fable 5’s, Anthropic expects them to intervene about 85% less often.

The idea, Anthropic says, is to leave room for defensive work like finding vulnerabilities in source code, while still blocking so-called “binary-based vulnerability scanning“, a technique Anthropic says is more likely to be associated with malicious actors.

When a classifier does flag a request in Claude.ai, Claude Code, or Cowork, it falls back to Opus 4.8 by default, and API users can enable the same behavior. Enterprises and researchers in Anthropic’s Cyber Verification Program get access to a version of Opus 5 with fewer of these restrictions.

Like other frontier labs, Anthropic is using this release to highlight the cost-effective nature of its models. At this point, every business is concerned about token cost and every lab is now sensitive to how the price of its models is perceived.

At this point, every business is concerned about token cost and every lab is now sensitive to how the price of its models is perceived.

Harvey, the legal AI company, saw its biggest gains with Opus 5 in practice areas like corporate governance and arbitration, says Niko Grupen, its head of applied research. “We were also impressed,” Grupen says, “with Opus 5’s ability to maintain quality at lower reasoning levels, achieving similar performance while generating 26% fewer tokens on average compared to Opus 4.8 at max reasoning.”

Opus 5 fast mode

Like Opus 4.8, Opus 5 will also offer a “fast mode,” both on the Claude Platform for developers and, by drawing down extra usage credits, in Claude Code. It will generate output tokens 2.5x faster and cost 2x more.

There are also two smaller platform updates that launch in beta today. With automatic fallbacks, API requests that Anthropic’s safety classifiers decline on Opus 5 or Fable 5 can automatically route to another model within the same request, instead of returning an error. Developers can also now change which tools Claude can use mid-conversation without invalidating the prompt cache, so each phase of an agent’s work only sees the tools it needs.

Opus 5 is available today on all of Anthropic’s paid plans and on the Claude Platform as claude-opus-5.

Background

While Opus 4 launched in May 2025, it was Opus 4.5 in November and Opus 4.6 in February 2026 that cemented the model family’s reputation as one of the best (and, at times, the best) models for coding.

For many users, Opus 4.7, which launched in April 2026, was a bit of a disappointment, which maybe explains why Anthropic released the well-received Opus 4.8 only a month-and-a-half later.

With Mythos and Fable, Anthropic more recently created a new tier of flagship models, but the company says it expects Opus 5 to be “the model we’d expect people to reach for every day, especially in the enterprise.”

OpenAI recently launched its GPT-5.6 Sol, Terra, and Luna family, with the Sol flagship model slightly more expensive than Opus 5 at $5/$30 per million input/output tokens. In the benchmark table Anthropic shared with this launch, Sol beats Opus 5 on just one of those benchmarks, the agentic coding test DeepSWE v1.1 (72.7 percent vs. 68.8 percent). Everywhere else, Anthropic is ahead, including on knowledge work, computer use, and business workflows.

Google’s Gemini models, meanwhile, don’t appear in Anthropic’s comparison table at all. Apparently, Anthropic didn’t think they rated an extra column.

The post Anthropic’s Opus 5 is almost Fable 5 appeared first on The New Stack.

Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Faces, Voices & Documents — On-Device Recognition Controls for .NET MAUI

1 Share
A MAUI UI July post: two drop-in MAUI controls — FaceRecognitionView and FaceEnrollmentView — that put live face recognition and a guided enrollment wizard on screen in one line of XAML, plus the CameraView frame analyzer, a GraphicsView overlay with an even-odd scrim, speaker recognition, and Shiny.DocumentDb + sqlite-vec as the on-device vector database.
Read the whole story
alvinashcraft
30 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Giving your .NET MAUI a real set of AI Wings

1 Share
A .NET MAUI app built straight on Microsoft.Extensions.AI — an IChatClient onto OpenAI, ChatOptions.Tools, and UseFunctionInvocation running the loop. The chat UI is a control; the hands are Shiny — contacts, reminders, GPS, health, music, a local document DB, your own services, and the app's own navigation. All opt-in, all switchable, all AOT-clean.
Read the whole story
alvinashcraft
33 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Blazor Basics: Handling Loading, Empty and Error States in Blazor

1 Share

Learn two ways to properly handle the four loading states: loading, error, success and empty in Blazor web applications.

In modern web development, page rendering speed is crucial. We render pages as quickly as possible and asynchronously load data from the server. Once the data arrives on the client, we update the web application and integrate the data into the existing page.

Therefore, modern data-driven applications are rarely in a stable state. Data might still be loading from the server, the request might fail or the server might return an empty data set.

Handling different application states is essential for creating responsive and user-friendly web applications.

In this article, we will learn how to professionally handle success, loading, empty and error states in Blazor web applications.

You can access the code used in this example on GitHub.

Basic Loading State Handling

When creating a Blazor Web App based on the .NET 10 project template, you’ll see code like this in the generated Weather page.

@foreach (var forecast in forecasts)
{
    <tr>
        <td>@forecast.Date.ToShortDateString()</td>
        <td>@forecast.TemperatureC</td>
        <td>@forecast.TemperatureF</td>
        <td>@forecast.Summary</td>
    </tr>
}

There is a forecasts field in the @code section of the component of type WeatherForecast[]?.

In the OnInitializedAsync lifecycle method, the forecasts field gets populated with the Weather data.

But what about the initial page render when the forecasts field is null?

If we use the foreach iteration statement on a null value, we’ll get a NullReferenceException during runtime. To prevent that from happening, the default project template wraps the above code in an if-else statement:

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else 
{
  // additional code omitted for simplicity
  @foreach (var forecast in forecasts)
  {
      <tr>
          <td>@forecast.Date.ToShortDateString()</td>
          <td>@forecast.TemperatureC</td>
          <td>@forecast.TemperatureF</td>
          <td>@forecast.Summary</td>
      </tr>
  }
}

As long as the value of the forecasts field is null, the Loading… text is shown on the page. When the forecasts field is populated during page initialization, the page rerenders and the else block is executed, which contains a foreachstatement that iterates over each element of the forecasts array.

While this basic setup works, it has some flaws.

  1. First of all, it’s cumbersome to wrap the whole page code inside a large if-else block.
  2. Next, the Loading… text is a lot smaller than the actual data rendering. That leads to vertical content shift during page load. Assume a button is below the forecast items. The user might want to click the button at the same time the list appears, moving the button away from their cursor.
  3. This basic implementation also doesn’t handle the error case. Let’s say the data doesn’t load from the server for various reasons; the Loading… text will forever be visible. It’s not possible to distinguish between the null value from the page initialization and the null value from a failed data loading attempt.

The goal of this article is to show you how to do a better job handling the empty, loading and error states of Blazor components.

Handling Empty Result Sets

Sometimes the HTTP requests to the server succeeds but returns no items.

In the previous example, we would show an empty list, since the foreach statement will not be executed because the returned list does not contain any items.

A better solution is to explicitly communicate the empty result set to the user. The following code properly differentiates the loading from the empty result set state.

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else if (!forecasts.Any())
{
    <p>No weather information available.</p>
}
else 
{
  // additional code omitted for simplicity
  @foreach (var forecast in forecasts)
  {
      <tr>
          <td>@forecast.Date.ToShortDateString()</td>
          <td>@forecast.TemperatureC</td>
          <td>@forecast.TemperatureF</td>
          <td>@forecast.Summary</td>
      </tr>
  }
}

This solution clearly communicates the three different UI states: Loading, empty result set and weather information available.

Handling Errors During Data Loading

Another often-overlooked case is when an HTTP request to the server fails.

With the previous implementation, the forecasts field will remain null or set to an empty list (depending on the implementation). Both options are wrong.

It’s best practice to show an error to the user to let them know that something didn’t work properly. Otherwise, they might think that the request returned an empty result set (meaning, no weather data is available).

Consider the following data loading implementation in the OnInitializedAsync lifecycle method:

private List<WeatherForecast>? forecasts;
private string? errorMessage;

protected override async Task OnInitializedAsync()
{
    try
    {
        forecasts = await weatherService.GetWeatherDataAsync();
    }
    catch (Exception ex)
    {
        errorMessage = ex.Message;
    }
}

We use a try-catch statement to catch exceptions and store the exception message in the errorMessage field.

Hint: It’s best practice to catch and properly handle different exception types. If we cannot recover from a specific exception type, it doesn’t make sense to catch it.

In the component template, we can now show the error message to the user:

@if (errorMessage != null) 
{
    <p class="text-danger">Error: @errorMessage</p>
}
else if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else if (!forecasts.Any())
{
    <p>No weather information available.</p>
}
else 
{
  // additional code omitted for simplicity
  @foreach (var forecast in forecasts)
  {
      <tr>
          <td>@forecast.Date.ToShortDateString()</td>
          <td>@forecast.TemperatureC</td>
          <td>@forecast.TemperatureF</td>
          <td>@forecast.Summary</td>
      </tr>
  }
}

We first handle the error case before considering the error, loading, empty and success states, using an extended if-else statement with four cases.

A Cleaner State Handling Pattern with Explicit State

Let’s look at a more scalable and less cumbersome approach to handling different loading states using an explicit state enum.

First, we implement a LoadingStates enum with four states: Loading, Success, Empty and Error:

public enum LoadingStates
{
    Loading,
    Success,
    Empty,
    Error
}

Next, we add a LoadingState component:

@if (State == LoadingStates.Loading)
{
    @Loading
}
else if (State == LoadingStates.Success)
{
    @Success
}
else if (State == LoadingStates.Empty)
{
    @Empty
}
else if (State == LoadingStates.Error)
{
    @Error
}

@code {
    [Parameter, EditorRequired]
    public LoadingStates State { get; set; }

    [Parameter]
    public RenderFragment? Loading { get; set; }

    [Parameter]
    public RenderFragment? Success { get; set; }

    [Parameter]
    public RenderFragment? Empty { get; set; }

    [Parameter]
    public RenderFragment? Error { get; set; }
}

We have a required State parameter of type LoadingStates, which will receive the current state of the parent component.

The Loading, Success, Empty and Error properties provide an optional parameter of type RenderFragment. Those properties are then used depending on the state of the parent component.

Hint: You can learn more about templating Blazor components with RenderFragements.

Next, we use the LoadingState component inside the Weather component:

<LoadingState State="@_loadingState">
    <Loading>
        <p><em>Loading...</em></p>
    </Loading>
    <Empty>
        <p>No weather information available.</p>
    </Empty>
    <Success>
        <table class="table">
            <thead>
                <tr>
                    <th>Date</th>
                    <th aria-label="Temperature in Celsius">Temp. (C)</th>
                    <th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
                    <th>Summary</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var forecast in forecasts)
                {
                    <tr>
                        <td>@forecast.Date.ToShortDateString()</td>
                        <td>@forecast.TemperatureC</td>
                        <td>@forecast.TemperatureF</td>
                        <td>@forecast.Summary</td>
                    </tr>
                }
            </tbody>
        </table>
    </Success>
    <Error>
        <p class="text-danger">Error: @errorMessage</p>
    </Error>
</LoadingState>

Instead of the if-else statement, we use the LoadingState component and provide the loading state of the Weather component as its State parameter.

We can now provide HTML definitions for each of the four loading states. For example, we move the table rendering the weather information into the Success child element.

The code section looks like this:

@code {
    private IEnumerable<WeatherForecast> forecasts = [];
    private LoadingStates _loadingState = LoadingStates.Loading;
    private string? errorMessage;

    protected override async Task OnInitializedAsync()
    {
        _loadingState = LoadingStates.Loading;

        try
        {
            forecasts = await WeatherService.GetWeatherDataAsync();
            _loadingState = forecasts.Any() ? 
                LoadingStates.Success : 
                LoadingStates.Empty;
        }
        catch (Exception ex)
        {
            errorMessage = ex.Message;
            _loadingState = LoadingStates.Error;
        }
    }
}

In addition to the forecasts field, we have a _loadingState field and an errorMessage field.

In the OnInitializedAsync method, we first set the loading state to Loading. This allows the Blazor application to communicate that it’s loading data by rendering the Loading state fragment defined in the component template.

Next, we use a try-catch statement to handle unexpected exceptions. In the try clause, we use the WeatherService to fetch the data from the server and set the _loadingState field to Success or Empty depending on the data received.

In case of an exception, we set the error message to the errorMessage field in the catch block and set the _loadingState field to Error.

Hint: You can test the error state by voluntarily throwing an exception inside the WeatherService implementation.

Improved Developer Experience

Optional: You could implement default behavior inside the LoadingState component for the loading and error cases.

That way, you maintain consistency throughout the application and can override the default implementation in specific cases. And you shorten the component template for most components, such as the Weather component in this example.

@if (State == LoadingStateEnum.Loading)
{
    @Loading ?? <p>Loading...</p>
}

In the LoadingState component, we use the ?? operator to render the provided render fragment or the default template.

You could do the same for the Error state or maybe even the Empty state.

Conclusion

In data-driven applications, handling states such as loading, error, empty and success is crucial for providing a modern user experience.

The default project template doesn’t provide a solution to handle all of them. It focuses on the happy path while neglecting other cases.

In this article, we learned two ways to properly handle the four loading states. The second approach, using a dedicated LoadingState component, is more reusable and clearly differentiates between all the states.

If you want to learn more about Blazor development, watch my free Blazor Crash Course on YouTube. And stay tuned to the Telerik blog for more Blazor Basics.

Read the whole story
alvinashcraft
49 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Build Bulletproof APIs using TypeScript in Express

1 Share

If you've ever loved the speed of building backend servers with Express.js, but wished you didn't have to guess at types or debug silly runtime errors, we just posted the perfect tutorial for you.

Our new video course, TypeScript in Express, is now live on the freeCodeCamp.org YouTube channel!

In this hands-on tutorial, instructor Rachel takes you step-by-step through combining Express with TypeScript, giving you the best of both worlds: the rapid development speed of Express paired with the scalability, reliability, and robust safety of strong typing.

Throughout the course, you’ll build a fully typed, production-ready pet shelter API from scratch. Along the way, you'll tackle:

  • Environment Setup: Configuring TypeScript, setting up compiler options (tsconfig.json), and managing development dependencies like @types/express.

  • Request & Response Typing: Moving away from the dreaded any type by leveraging TypeScript generics to strictly define route parameters, request queries, and response bodies.

  • Modular Architecture: Cleaning up your project structure by separating your endpoints into dedicated Express routers and controllers.

  • Custom Middleware: Writing and typing your own middleware functions from scratch—including input validators and authentication checks.

  • Query Parameter Filtering: Handling string, boolean, and numeric query filters to make your APIs flexible and real-world ready.

Whether you're looking to solidify your backend skills or bring stronger type safety to your Node.js projects, this course is packed with practical challenges and coding exercises to keep you on your toes.

Watch the full tutorial on the freeCodeCamp.org YouTube channel (1-hour watch).



Read the whole story
alvinashcraft
59 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Faster blob copying in Azure Blob Storage

1 Share

I generally try to avoid copying blobs in Azure and just reference a single copy, but there are some situations where you do need to make a copy. The technique you choose can make a big difference to how long that copy takes.

For example, the "naive" approach of downloading the source and re-uploading it to the destination is conceptually simple but likely to be very slow. On my laptop, a 10GB copy using this technique took about one hour, but that same copy can be done server side in minutes, and if you use a parallel block copy approach (similar to that used by AzCopy) you can copy a file of this size in seconds.

In this post, I'll explain three approaches to blob copying and share some timings.

Download and re-upload (Avoid!)

The "naive" approach is to open the source as a stream and then upload it straight back up:

await using var src = await source.OpenReadAsync();
await using var dst = await target.OpenWriteAsync(overwrite: true);
await src.CopyToAsync(dst);

The problems here are first that the speed is bound by your local connection (about 25 Mbps in my tests), and you're paying for egress bandwidth.

The only situation where this approach makes sense is if for some reason you need to transform the data during the copy (in which case it's not really a copy anyway!)

Server-side copy (StartCopyFromUriAsync)

There's a much better approach offered by the Azure Blob storage SDK, where you generate a SAS URI for the source (typically a short-lived user-delegation SAS) and it performs the copy for you server-side. This operation is asynchronous and you are expected to poll until it completes.

var copy = await target.StartCopyFromUriAsync(sourceSasUri);
await copy.WaitForCompletionAsync();   // poll until Azure finishes

There are several benefits here - you're not streaming any data through your machine, and you're not paying egress cost. It's also robust - the copy continues even if your process goes down after initiating the copy.

This approach was my preferred technique for all blob copies until I noticed that it doesn't perform nearly as fast as AzCopy when copying across storage accounts.

Parallel block-from-URL copy

If you really want the fastest cross-storage account copying speed, the technique I've used is to mimic how AzCopy behaves and split the source blob into ranges and use a technique that allows you to stage blocks from a URL. This means that you can instruct Azure to copy many blocks in parallel. Once all the blocks are staged, you then commit the list of blocks.

You will need to decide what block size to use. A block blob can have up to 50,000 blocks, so if you're copying vast files you need to use sufficiently large block sizes (say 100MiB if you want to upload multi-TiB files). In the example below I also show how to limit the number of blocks that are staged at a time.

const long blockSize = 100 * 1024 * 1024; // 100 MiB

var length = (await source.GetPropertiesAsync()).Value.ContentLength;

// pre-compute an ordered (blockId, range) list — block IDs must be equal-length strings
var blocks = new List<(string Id, HttpRange Range)>();
for (long offset = 0; offset < length; offset += blockSize)
{
    var blockId = Convert.ToBase64String(
        Encoding.UTF8.GetBytes($"block-{blocks.Count:D6}"));
    blocks.Add((blockId, new HttpRange(offset, Math.Min(blockSize, length - offset))));
}

// stage up to 8 blocks at a time
await Parallel.ForEachAsync(blocks,
    new ParallelOptions { MaxDegreeOfParallelism = 8 },
    async (block, ct) =>
        await target.StageBlockFromUriAsync(sourceSasUri, block.Id,
            new StageBlockFromUriOptions { SourceRange = block.Range },
            cancellationToken: ct));

// commit in order (the list is already ordered)
await target.CommitBlockListAsync(blocks.Select(b => b.Id));

With this approach, again the bytes are never downloaded to your machine, and this gives a great speed-up. Of course, unlike with StartCopyFromUriAsync you'll need to make sure that you handle resilience - if you're interrupted half-way through, you'll need to finish staging blocks and committing the block list once they're all done.

Copying within the same storage account

An important caveat is that if the source and destination blobs are in the same storage account, you should just use the server-side copy technique with StartCopyFromUriAsync. It's essentially instantaneous regardless of blob size. For example, in my tests, a 10 GB same-account server-side copy completed in under a second, compared with ~17 s for the parallel copy technique (which still has to transfer the entire file as blocks).

Example timings

I tried each of these three techniques for files of various sizes (100MB, 1GB, 10GB), and between storage accounts in the same and different regions, as well as within a storage account.

Scenario Size Server-side Parallel Naive
Same region (cross-account) 100 MB 31.5 s 2.7 s 35.9 s
Same region (cross-account) 1 GB 65.2 s 2.4 s 5m 56s
Same region (cross-account) 10 GB 4m 04s 9.2 s 72m 02s
Cross region (cross-account) 100 MB 20.9 s 2.4 s 31.0 s
Cross region (cross-account) 1 GB 92.1 s 2.9 s 5m 00s
Cross region (cross-account) 10 GB 4m 39s 21.2 s 53m 33s
Same account 100 MB 0.7 s 1.5 s 32.6 s
Same account 1 GB 0.4 s 3.0 s 4m 41s
Same account 10 GB 0.4 s 16.8 s 54m 55s

As you can see, the parallel copy technique is by far the fastest in all situations except same-account copies.

Important caveats: I only did one timing for each scenario, and of course the naive copy is more a measure of how fast my local internet connection was working than anything to do with how fast Azure blob storage works. I also did the parallel copy without constraining the number of blocks in parallel at all (which could have been about 100 for the largest file).

Is it an exact copy?

I validated that the parallel copy technique resulted in the same file hash, so yes, this technique does faithfully replicate the original file contents. But of course there is more to a blob than just its contents.

Azure blobs can also have metadata, tags, and properties. Each of the three techniques will allow you to also copy these across, but you must opt in (and ensure that any readable SAS URI for the source file has permissions to access this metadata). See my earlier tutorial here for guidance on copying metadata.

Azure blobs are also stored in an access tier (e.g. hot, cold, cool, archive). Unless you explicitly specify a target tier, you'll just use the account default. And of course if your source blob is in archive, it will need to be rehydrated first, which could be a very slow process.

Block blobs are made up of a series of blocks. With the parallel technique, we ignore the block structure of the source file, and recreate a new blob with (typically fewer) blocks than the source blob. This rarely matters but is worth being aware of.

Summary

If you need to copy blobs between storage accounts, the fastest technique I'm aware of is the parallel block-from-URL copy. This keeps the data off your machine and is by far the quickest for anything non-trivial. The key exception is whenever you copy within a single storage account, where you should just use the plain server-side copy as it's effectively instantaneous. And avoid the download and re-upload approach to blob copying.

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories