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

What’s new in Microsoft Foundry | Build Edition

1 Share

TL;DR

At Build 2026, Microsoft Foundry added more of the platform pieces developers need for production agents: runtime, tools, memory, grounding, models, observability, and governance. This recap highlights what shipped, what is in preview, and where to start.

  • Agent development got faster: Microsoft Agent Framework adds stable orchestration building blocks, and Foundry Toolkit for VS Code is now generally available.
  • Production agent hosting matured: hosted agents are expected to reach general availability by early July 2026, with sandboxed sessions, state, filesystem access, and framework flexibility.
  • Agents can connect to more tools and channels: Toolboxes in Foundry is in public preview, Voice Live adds real-time voice paths, and Foundry agents can publish to Microsoft Teams and Microsoft 365 Copilot, planned for general availability in June 2026.
  • Agent memory expanded: Memory in Foundry Agent Service, in public preview, now includes procedural, user, and session memory.
  • Foundry IQ became a broader knowledge plane: serverless retrieval, new knowledge sources, knowledge bases, Web IQ, security updates, and agentic retrieval improvements reduce custom retrieval-augmented generation (RAG) plumbing.
  • Model and compute options expanded: new MAI models, Fireworks AI on Foundry, Managed Compute, fine-tuning, and Frontier Tuning give developers more choices for inference, training, and customization.
  • Trust, evaluation, and observability moved closer to the development loop: ASSERT, Agent Control Specification (ACS), Guided Guardrail Setup, Rubric, tracing, Agent Optimizer, and Agent ROI help teams evaluate, govern, and improve agents.

Start here: what to try first

If you only have time to try one thing, start with the row that matches your current build problem:

If you are building… Start with… Why it matters
A production agent runtime Hosted agents in Foundry Agent Service Managed sandboxed sessions, state, filesystem access, and framework flexibility
An agent with many tools Toolboxes in Foundry One governed endpoint for tools, skills, Model Context Protocol (MCP) clients, and enterprise data
An enterprise knowledge experience Foundry IQ knowledge bases SLA-backed retrieval and MCP access without custom indexing glue
A real-time voice agent Voice Live Speech recognition, text-to-speech, turn detection, interruption handling, and avatars in one API
Agent safety and evaluation workflows ASSERT, ACS, and Rubric Policy-driven evaluations, deterministic runtime controls, and generated scoring criteria
Model experimentation or custom inference Fireworks AI on Foundry, MAI models, and Managed Compute More model options through Azure endpoints with enterprise controls

Developer tools and SDKs

The updates in Microsoft Agent Framework give developers more stable building blocks for agent applications:

  • Agent harness with skills, memory, and middleware, now in stable release.
  • Integrations with GitHub Copilot SDK and Claude Agent SDK, now in stable release.
  • Multi-agent orchestration patterns including Magentic-One, now in stable release.
  • File system tools, memory tools, and the deep research agent, now in public preview.

Foundry Toolkit for VS Code is now generally available. Use it to create agents from templates or with GitHub Copilot, debug runs locally with trace visualization, connect to Toolboxes, and deploy to Foundry Agent Service from VS Code.

Animated demo of the Foundry Toolkit for VS Code showing agent development and debugging workflows.

Try this next: Open Foundry Toolkit in VS Code, create an agent from a template, and run it locally before deploying it to Foundry Agent Service.

Watch: Build smarter AI systems in Foundry as models and costs evolve for model selection, benchmarking, and developer workflow guidance in Microsoft Foundry.

Agents

Build 2026 adds more of the pieces developers need to move agents from prototypes to production:

Capability Status Use when…
Hosted agents Expected general availability by early July 2026 You need managed runtime, sandboxing, state, durable filesystem access, and framework flexibility
Routines Public preview You want an agent to run on a timer or schedule, such as overnight issue triage or daily reporting
Toolboxes Public preview You need one managed endpoint for tools, skills, MCP clients, and governance
Voice Live prompt agents Generally available You want the fastest path to a real-time voice experience
Hosted voice agents Public preview You want your own runtime or orchestration framework connected to Voice Live
Memory Public preview You want agents to retain procedural, user, or session context
Teams and Microsoft 365 Copilot publishing Planned for general availability in June 2026 You want users to access your Foundry agent where they already work

Deploy production agents with hosted agents and routines

Hosted agents in Foundry Agent Service, expected to reach general availability by early July 2026, provide a managed runtime for production agents. Every session runs in its own sandbox with dedicated compute, memory, and filesystem access.

The runtime is framework-agnostic, so agents built with Microsoft Agent Framework, GitHub Copilot SDK, LangGraph, or other software development kits (SDKs) can be deployed without rewrites. Two protocols are supported:

  • Responses API for OpenAI-compatible stateful interactions.
  • Invocations protocol for schema-free, pass-through scenarios where you control the request and response format.

Hosted agents now support long-running autonomous agents like OpenClaw and Hermes with durable state and filesystem access, and routines, in public preview, for running any agent on a timer or schedule.

Try this next: Explore the sample code with Microsoft Agent Framework, then deploy an agent to hosted agents.

Watch: From prototype to production: build and run agents at scale for the hosted-agent runtime story.

Toolboxes and skills

Toolboxes in Foundry, in public preview, gives your agent a single managed endpoint for every tool type. Configure tools once, point any MCP client at one URL, and let Foundry handle auth, lifecycle, and governance.

Skills, in preview, are now first-class: versioned in a project-scoped catalog and discoverable as MCP resources by any agent in the project. Tool search, also in preview, helps select the right tools per task instead of surfacing every tool to the model.

Toolbox also connects to Microsoft IQ, including Work IQ in preview, Fabric IQ in preview with Fabric data agent, Ontology, and semantic models, and Foundry IQ, so agents can tap enterprise data without custom plumbing.

Animated demo of the Microsoft Foundry Toolboxes interface showing a catalog of tools, versions, and descriptions.

Try this next: Create a Toolbox, connect it to an MCP-compatible client, and test the Microsoft Agent Framework and Toolbox sample.

Watch: Turn your agents into action: Connect tools, APIs, and documents for tool, API, and Toolbox patterns.

Voice Live

Voice Live unifies speech recognition, text-to-speech, turn detection, interruption handling, avatars, and other real-time conversational features into a single API.

For teams building with prompt agents, Voice Live is now generally available as the fastest path to adding real-time voice experiences. Existing agent capabilities, including tool calling, knowledge, memory, guardrails, and enterprise integrations, can now use low-latency speech interactions.

For teams that need full control over runtime and orchestration, hosted agents with Voice Live are available in public preview. Developers can use Microsoft Agent Framework, LangChain, or a custom stack, host on Foundry Agent Service, and connect directly to Voice Live.

Try this next: Use Voice Live with a prompt agent if you want the shortest path to voice, or pair hosted agents with Voice Live if you need custom orchestration.

Memory

Memory in Foundry Agent Service, in public preview, now includes three types:

  • Procedural memory, new at Build in public preview, helps agents learn how to do the work across runs, not just what was said. Early Tau-bench results show +7–14% absolute success-rate gains at near-baseline cost.
  • User memory remembers preferences and facts across sessions, such as “user is allergic to dairy.”
  • Session memory maintains context within a conversation thread.

Try this next: Enable memory on a test agent and compare task success, tool calls, and token use across repeated runs.

Publish agents where people work

With publishing to Microsoft Teams and Microsoft 365 Copilot, planned for general availability in June 2026, any Foundry agent can be deployed directly into the tools employees already use, with identity, permissions, and policy flowing through automatically.

Animated demo showing a Foundry agent published into a Microsoft business application experience.

Try this next: Publish a low-risk internal agent to Teams, validate permissions, and then expand to Microsoft 365 Copilot.

Knowledge and grounding

Grounding an agent in enterprise knowledge usually means building a retrieval-augmented generation (RAG) pipeline from scratch: chunking, indexing, retrieval, and a different integration for every data source.

Foundry IQ replaces that with a dedicated knowledge layer behind your Foundry agents. It unifies Work IQ, Fabric IQ, Azure SQL, File Search, and MCP sources behind one service-level agreement (SLA)-backed retrieval endpoint. Foundry IQ is available today and is wired into Toolboxes in Foundry, so agents can tap enterprise data without custom plumbing.

Foundry IQ update Status Developer action
Foundry IQ Serverless Public preview Create a Foundry IQ resource or review the SKU documentation
New knowledge sources Public preview Ground agents across Work IQ, Fabric IQ, File Search, Azure SQL, and MCP with a multi-source knowledge base; start with the cookbook
Microsoft Web IQ in Foundry IQ Limited access Use live web, licensed publisher, and marketplace data when your agent needs fresh external context
Foundry IQ knowledge bases Generally available Create an SLA-backed knowledge base and query it with the quickstart
Agentic retrieval quality improvements Available Compare answer quality, latency, and token use with the agentic retrieval quickstart
Security updates Public preview Test encryption, permission sync, and sensitivity-label governance with the security cookbook
Data pipeline updates Public preview Use layout-aware ingestion, image serving, and broader SharePoint indexing when documents include more than raw text

When your agent needs the live web, Web IQ provides sub-200 ms web grounding with zero data retention. It surfaces browse, news, web, video, and image results and is available today for select Azure customers.

Both Foundry IQ and Web IQ roll up into Microsoft IQ, the generally available intelligence layer for connecting work data, business data, and agent knowledge.

Watch: Foundry IQ: Fuel agents with enterprise knowledge and agentic retrieval and Build context-aware agents: From data to decisions for the grounding and IQ deep dive.

Models and compute

New MAI models in Microsoft Foundry

Microsoft’s MAI model family expands in Microsoft Foundry with four first-party models entering public preview at Build:

  • MAI-Thinking-1, a mid-weight large language model for chat and reasoning.
  • MAI-Image-2.5, an updated image generator with image-to-image editing.
  • MAI-Transcribe-2, a speech-to-text model with speaker diarization and content biasing.
  • MAI-Voice-2, a multilingual text-to-speech model with voice cloning.

Together, they cover the four core generative modalities: text, image, transcription, and voice.

Action: Try the new models in the Foundry catalog.

Fireworks AI on Foundry

Fireworks AI on Microsoft Foundry is now generally available, bringing open-model inference through a single Azure endpoint with enterprise SLAs, zero-setup onboarding, no separate infrastructure, and no separate contracts.

Fireworks AI on Foundry provides day-zero access, low latency, high throughput, and support for custom-weight models. It is validated for enterprise use with provisioned throughput unit (PTU) Data Zone support and SOC 2 readiness, governed by the same access controls and audit logging as the rest of Foundry.

Action: Spin up a Fireworks endpoint from the Foundry catalog and benchmark latency, quality, and throughput against your current setup.

Managed Compute in Foundry Models

Use Managed Compute in Foundry Models when regional GPU capacity is the bottleneck and you want Foundry to route workloads globally without managing infrastructure.

  • Capacity: route around regional GPU constraints without managing infrastructure.
  • Fine-tuning: spin up flexible compute for bespoke model training.
  • Operations: reduce infrastructure management for model workloads.

Action: Try Managed Compute for a workload that currently depends on capacity in one region.

Fine-tuning and Frontier Tuning

Fine-tuning in Foundry delivers higher-quality results than prompt engineering alone, broader example coverage, token savings, and lower-latency requests on smaller models. Frontier Tuning is more than 10x more cost-efficient than GPT-5.5 on tasks like producing technical Microsoft documentation.

Action: Try the new developer tier for fine-tuning: no hosting fees, just experiment.

Watch: Post-Training and Deploying Open Source Reasoning Models in Foundry, Turn foundation models into production AI on Microsoft Foundry, and Orchestrate special agents with NVIDIA Nemotron models on Foundry for model customization and open-model deployment patterns.

Trust, observability, and security

Build also introduced new ways to evaluate, control, and improve agents across the development lifecycle:

Capability Status Use when…
ASSERT Open source You want to turn written policies into executable agent evaluations
Agent Control Specification Open source You need deterministic controls at input, model, state, tool, and output checkpoints
Guided Guardrail Setup Public preview You want recommended guardrails based on your agent’s audience, data, and use case
Rubric evaluator Public preview You want generated, weighted quality criteria for an agent-specific scorecard
Tracing and evaluations for any framework Public preview You need observability for agents built on LangChain, Semantic Kernel, or custom frameworks
Agent Optimizer Coming soon in public preview You want production traces to feed ranked, reviewable improvement suggestions
Agent ROI Private preview You need to connect agent performance to business impact

Watch: Observe and control agents across any framework with open source tools, From observability to ROI for AI agents on any framework, and Build secure and enterprise-ready agents with Agent 365 for the trust, observability, and governance track.

ASSERT: open-source policy-driven agent evaluation

ASSERT is Microsoft’s new framework for policy-driven agent evaluation, built on a proven Microsoft Research approach. ASSERT converts your policies into concrete, measurable evaluations, systematically generates targeted evaluation scenarios, and surfaces safety and quality defects before they reach production.

ASSERT is open source and works across LangChain, CrewAI, LightLLM, OpenAI, and more.

Resources:

Action: Clone the ASSERT GitHub repository and run it against your agent’s policies.

Agent Control Specification: an open standard

Agent Control Specification (ACS) is an open industry specification for placing deterministic safety and security controls at five checkpoints in an agent’s lifecycle: input, large language model (LLM), state, tool execution, and output.

ACS is expressed as a portable YAML contract: versionable, auditable, and framework-agnostic. Reference implementations are available for major platforms, and the partner ecosystem at launch includes Infosys, KPMG, IBM, Aviatrix, BigSpin, and CrewAI.

Resources:

Action: Review the Agent Control Specification, then use the Agent Governance Toolkit to apply controls at checkpoints.

Guided Guardrail Setup in Foundry Agent Builder

Guided Guardrail Setup in Foundry Agent Builder is in public preview. A short questionnaire about your agent’s audience, data access, and use case surfaces the risks relevant to your scenario and recommends the right controls, such as personally identifiable information (PII) filters, jailbreak protection, and task adherence, with no security expertise required.

Action: Run the Guided Guardrail Setup wizard on your next agent.

Rubric evaluator

Rubric is a new evaluator type in Microsoft Foundry, in public preview, that auto-generates evaluation criteria based on your agent’s specific context. It creates custom quality criteria from your agent definition and use case, supports weighted dimensions for aggregate scoring, and runs alongside existing safety and quality evaluators for a unified scorecard. It also feeds directly into Agent Optimizer.

Action: Generate a Rubric for your agent and replace your static benchmarks.

Tracing, evaluations, optimization, and ROI

Tracing and evaluations for any agent framework, in public preview, brings Foundry’s production-grade tracing and evaluations to agents built on LangChain, Semantic Kernel, or any custom framework, so no team has to choose between its stack and observability.

Agent Optimizer in Foundry Agent Service, coming soon in public preview, runs Foundry’s full evaluation suite directly within Foundry AI Operations Service and feeds results into Foundry Optimizer, closing the loop from production signal to ranked, reviewable improvements.

ROI for agents in Foundry, in private preview, measures the real business impact of your agents, including task completion rates, time saved, and cost efficiency, giving stakeholders the data they need to justify investment and prioritize what to improve.

Resources and community

The post What’s new in Microsoft Foundry | Build Edition appeared first on Microsoft Foundry Blog.

Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Getting Started with SignFabric: From Clone to Your First Signature Envelope

1 Share
In this blog post, we will guide you through the process of getting started with SignFabric, from cloning the repository to creating your first signature envelope. Whether you are new to SignFabric or looking to refresh your knowledge, this step-by-step guide will help you set up and use SignFabric effectively.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Launching the Rust Foundation Maintainers Fund

1 Share

If you want to financially support the development of Rust, please consider donating to the Rust Foundation Maintainers Fund.

A few months ago, the Rust Foundation announced the Rust Foundation Maintainers Fund (RFMF). Since then, the Rust Project has been closely cooperating with the Rust Foundation to determine how exactly this fund will be used to support Rust maintainers. This resulted in the acceptance of RFC #3931, which established the Funding team and the Maintainer in Residence program.

The primary goal of the Funding team is to ensure that maintainers who work on Rust and its toolchain will be properly supported. We will talk to Rust Project members to figure out their funding situation, meet Rust team leads to learn about their maintenance needs, approach companies to find opportunities for them to invest into Rust by supporting Rust maintainers, coordinate various funding efforts and ensure that the beneficial effects of funded maintenance are visibly promoted, with the help of the Content team.

Maintainer in Residence is a new program dedicated to financially supporting existing Rust Project maintainers1. Each Maintainer in Residence will be funded to maintain one or more critical parts of Rust, such as the compiler, the standard library, Cargo, Clippy or one of many other projects that the Rust Project develops and maintains. The funded work will include activities such as performing large-scale refactorings, code reviews, unblocking new features, issue triaging, mentoring other contributors and more, and will be split between priorities guided by the teams they are supporting and priorities of their own choosing within the Project. Where applicable, Maintainers in Residence are also encouraged to propose, champion, and drive forward Rust Project Goals.

The goal of this program is to provide stable and long-term funding so that maintainers can focus on important work that ensures the long-term health of Rust. The funding team will select Maintainers in Residence based on funding availability and maintenance needs within the Rust Project, and help ensure that they are successful. We expect that this will usually be a (near) full-time position, but that will depend on the nature of the work and the area of maintenance.

This program extends our existing support for Rust maintainers, such as the program management program and the compiler-ops program. An important development is that we now have a centralized mechanism for gathering donations from both individuals and companies, and a dedicated team that will help direct those funds to specific maintainers. You can find more details about the funding team and the Maintainer in Residence program in the RFC.

We expect to hire the first Maintainer in Residence in the upcoming months and announce it on this blog, so stay tuned!

How to contribute funds

If you are an individual who wants to help Rust succeed and thrive, you can donate to the RFMF through GitHub Sponsors2. Companies who would like to invest in better maintenance of Rust can also donate through GitHub Sponsors or they can contact the Rust Foundation directly.

The important thing is that all proceeds from this fund will be directly used to support Rust Project maintainers. We currently expect that to happen primarily through the Maintainer in Residence program, but it can also be done in the form of smaller-scale grants or other mechanisms, as determined by the Funding team. We will figure this out on the go, as this is also quite new for us.

We really appreciate each donation, however small, because with more money we can hire more maintainers to ensure that we can continue to develop Rust and that important improvements are not blocked on maintenance tasks. This is especially important at this time, where Rust is starting to get used more and more in the industry in various application areas, which increases the need for sustained maintenance. The importance of multiple funding sources is underscored by an unfortunate trend we currently observe, where key Rust maintainers are losing their funding for Rust work due to budget shifts. The Rust Foundation Maintainers Fund is designed to provide stable funding for Rust maintainers that is less dependent on sudden shifts in the job market and the IT industry.

As with most things, there is no one-size-fits-all solution, so there are multiple ways to support Rust financially. The RustNL Maintainers Team recently hired several Rust Project maintainers. Previously, we wrote about how you can support specific individuals working on Rust. And there are also Rust Project Goals in search of funding. We welcome all efforts that can help support Rust Project maintainers, who often do work that is near invisible and thankless, while at the same time incredibly important and necessary, on a volunteer basis.

Thank you for considering sponsoring the development and maintenance of Rust! You can find more information about funding Rust on our Funding page.

  1. This program was inspired by the Developer in Residence concept used by the Python Software Foundation (PSF), with which we led several helpful discussions. Thank you, PSF!

  2. Note that the fact that GitHub Sponsors is currently enabled on the rustfoundation GitHub organization, and not the rust-lang organization, is an implementation detail that might change in the future. All donations raised on this Sponsors page will be routed to the Rust Foundation Maintainers Fund and will be spent on directly supporting Rust Project maintainers.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

XAML.io Compiles To Native Apps In Browser

1 Share
Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Pagination in EF Core, Continued: Sortable Grids, htmx, and the Indexing Cost

1 Share

The first post in this series made a clean case for keyset pagination over Skip/Take. Readers on LinkedIn pushed back with a fair question I’d dodged: what about sortable grids where the user picks the column? The post showed ORDER BY Id, which is the easy case. Real apps have grids with eight clickable column headers and a “sort direction” toggle.

This follow-up is the honest answer. It covers:

  • Where the original argument still holds, and where it underserved you
  • Keyset pagination with a fixed non-ID sort
  • Keyset pagination with dynamic sort columns
  • The indexing reality. Every sortable column is an index, and that’s expensive
  • When you should just use offset

Where the original argument holds and where it didn’t

Two things from the first post hold up under scrutiny:

Performance. OFFSET 10000 semantically requires producing and discarding 10,000 rows in sort order. There’s no index structure that lets the database “jump to the 10,001st row in this filtered, sorted result” without traversing what came before. You can verify this by checking that in any execution plan, rows read grow with the offset, and the rows returned are even when the r constant. This is true on SQL Server, PostgreSQL, and MySQL alike. It’s a property of what OFFSET means, not a database engine limitation.

Correctness under concurrent writes. If rows are inserted or deleted between page requests, offset skips or duplicates records silently. This is a correctness bug, not a performance issue, and it’s invisible until a user reports a missing record they swear they saw.

What the first post overlooked: the implementation cost of keyset scales with the dynamism of your sort requirements. A single fixed sort order is genuinely simple. Twelve user-selectable columns with mixed directions is more work, and that work has costs in code complexity and index storage. The post should have engaged with that trade-off rather than treating keyset as a universal upgrade.

So here’s the revised thesis: use keyset when the table is large AND write-heavy AND user-facing. Three ANDs, not ORs. If any of those is no, offset is probably fine and “probably fine” is not a hedge, it’s the honest answer.

Keyset with a fixed non-ID sort

The bridge case, before we tackle dynamic sorts. The user always sees orders sorted by CreatedAt DESC, newest first. This is the canonical “activity feed” or “order history” pattern.

The cursor needs two fields: the sort value and the primary key (as a tiebreaker, because CreatedAt isn’t unique).

public record OrderCursor(DateTime CreatedAt, int Id);
​
public async Task<List<Order>> GetPageAsync(OrderCursor? cursor, int pageSize)
{
    var query = _db.Orders.AsNoTracking().AsQueryable();
​
    if (cursor is not null)
    {
        query = query.Where(o =>
            o.CreatedAt < cursor.CreatedAt ||
            (o.CreatedAt == cursor.CreatedAt && o.Id < cursor.Id));
    }
​
    return await query
        .OrderByDescending(o => o.CreatedAt)
        .ThenByDescending(o => o.Id)
        .Take(pageSize)
        .ToListAsync();
}

Two things to notice. The tuple comparison handles the CreatedAt ties, without it, two rows sharing a millisecond timestamp could be silently skipped. And the OrderByDescending(o => o.Id) tiebreaker matters: it has to match the cursor’s logic exactly, or your results drift.

The supporting index:

CREATE INDEX IX_Orders_CreatedAt_Id ON Orders(CreatedAt DESC, Id DESC);

SQL Server can scan an ascending index backward, so CREATE INDEX ... (CreatedAt, Id) works too, but writing the index in the same direction as your query makes the intent explicit and prevents a future maintainer from “fixing” the sort order and breaking the seek.

Keyset with dynamic sort columns

Now, the case the LinkedIn commenters actually asked about. The user clicks a column header. Then a different one. Then toggles direction. The cursor needs to carry not just values but which column and direction those values belong to, otherwise a client could pass a CreatedAt cursor into a LastName-sorted query and get garbage.

Here’s the cursor shape:

public enum SortColumn { CreatedAt, Total, CustomerId, Status }
public enum SortDirection { Asc, Desc }
​
public record SortableCursor(
    SortColumn Column,
    SortDirection Direction,
    string KeyValue,   // serialized the column's type varies
    int Id);

KeyValue is a string because the type depends on which column we’re sorting by. Serializing to string keeps the cursor uniform on the wire and lets us round-trip it as a single opaque token.

The query builder dispatches on the column:

public async Task<(List<Order> Items, SortableCursor? Next)> GetPageAsync(
    SortableCursor? cursor, SortColumn column, SortDirection direction, int pageSize)
{
    var query = _db.Orders.AsNoTracking().AsQueryable();
​
    // Validate cursor matches the requested sort. If not, ignore it (page 1 in new order).
    if (cursor is not null && (cursor.Column != column || cursor.Direction != direction))
        cursor = null;
​
    query = (column, direction) switch
    {
        (SortColumn.CreatedAt, SortDirection.Desc) => ApplyCreatedAtDesc(query, cursor),
        (SortColumn.CreatedAt, SortDirection.Asc)  => ApplyCreatedAtAsc(query, cursor),
        (SortColumn.Total, SortDirection.Desc)     => ApplyTotalDesc(query, cursor),
        // ...one branch per (column, direction) pair
        _ => throw new ArgumentOutOfRangeException(nameof(column))
    };
​
    var items = await query.Take(pageSize).ToListAsync();
    var next = items.Count == pageSize
        ? BuildCursor(items[^1], column, direction)
        : null;
​
    return (items, next);
}
​
private static IQueryable<Order> ApplyCreatedAtDesc(IQueryable<Order> q, SortableCursor? c)
{
    if (c is not null)
    {
        var cursorDate = DateTime.Parse(c.KeyValue);
        q = q.Where(o =>
            o.CreatedAt < cursorDate ||
            (o.CreatedAt == cursorDate && o.Id < c.Id));
    }
    return q.OrderByDescending(o => o.CreatedAt).ThenByDescending(o => o.Id);
}

A few honest notes on this code:

  • The switch expression with one branch per (column, direction) pair is verbose but readable, type-safe, and produces clean SQL. The alternative, building expression trees dynamically, is more elegant in theory but harder to debug, profile, and review.
  • When the user changes sort columns, the cursor is reset. There’s no way to “translate” a cursor across sort orders, because different sorts mean different sequences of rows. The validation at the top of the method does this silently; you might prefer to return an error.
  • This is roughly 80 lines of code for four sortable columns. Compare to ~5 lines for offset. That’s a real cost.
  • For wire transport, base64-encode the JSON-serialized cursor. The client treats it as an opaque token.

The indexing reality

This is the section the LinkedIn commenter implicitly asked for, and most pagination posts skip. Sortable grids force a database design conversation, not just a query conversation.

The rule: every keyset-sortable column needs a covering composite index ending in the primary key. No exceptions. Without the matching index, the keyset WHERE clause falls back to a scan, and you’ve lost the entire benefit.

For four sortable columns in our Order example:

CREATE INDEX IX_Orders_CreatedAt_Id ON Orders(CreatedAt, Id);
CREATE INDEX IX_Orders_Total_Id     ON Orders(Total, Id);
CREATE INDEX IX_Orders_Customer_Id  ON Orders(CustomerId, Id);
CREATE INDEX IX_Orders_Status_Id    ON Orders(Status, Id);

A bidirectional sort (ascending and descending) on the same column generally doesn’t need two indexes. SQL Server can scan an index backward, but verify against your execution plans.

Now the cost math. For a 10M-row Order table with 8-byte bigint keys, a single composite index on (CreatedAt, Id) is roughly:

  • ~16 bytes per index entry (8 for datetime2, 8 for bigint), plus row locator and page overhead
  • Realistic on-disk size: ~250–350 MB per index
  • Four such indexes: roughly 1 GB of index storage for one table

That’s storage. The bigger hidden cost is write amplification: every INSERT updates every index. Every UPDATE that touches an indexed column updates that index. On a hot table doing 1,000 writes per second, four extra indexes can meaningfully increase your write latency and your transaction log volume.

Three takeaways:

  1. “Any column is sortable” is an expensive product promise. Often, the right answer is “users can sort by these three columns” rather than “users can sort by any of the twelve columns we display.”
  2. Audit your indexes against your sort options. A sortable column with no supporting index is worse than an offset. You get the keyset complexity and the scan cost.
  3. Watch the execution plan, not the wall clock. A query that runs in 12ms on an empty dev database can run in 2 seconds on a 50M-row production database if the index is missing. Wall-clock time during development is not evidence of correctness.

A working demo: Razor Pages + htmx

The pattern is small and worth understanding because it’s where keyset pagination feels most natural.

The page renders a table with clickable column headers. Each header is an htmx link that triggers a GET to ?handler=Sort&column=X&direction=Y, which returns a fresh <tbody> fragment:

<table>
  <thead>
    <tr>
      <th><a hx-get="?handler=Sort&column=CreatedAt&direction=Desc"
             hx-target="#orders-body"
             hx-swap="innerHTML">Created</a></th>
      <th><a hx-get="?handler=Sort&column=Total&direction=Desc"
             hx-target="#orders-body"
             hx-swap="innerHTML">Total</a></th>
      <!-- ... -->
    </tr>
  </thead>
  <tbody id="orders-body">
    <partial name="_OrdersRows" model="Model.Page" />
  </tbody>
</table>

The “load more” row is the bottom row of the partial. It carries the next cursor and triggers when the user scrolls it into view:

@if (Model.NextCursor is not null)
{
    <tr hx-get="?handler=LoadMore&cursor=@Model.NextCursor&column=@Model.Column&direction=@Model.Direction"
        hx-trigger="revealed"
        hx-swap="outerHTML">
        <td colspan="5">Loading…</td>
    </tr>
}

The hx-trigger="revealed" is the magic. When the placeholder row scrolls into the viewport, htmx fires the GET, the server returns more <tr> elements plus a new sentinel row with the next cursor, and hx-swap="outerHTML" replaces the sentinel with the new rows. Infinite scroll, server-rendered, ~30 lines of total markup.

The handler is straightforward Razor Pages:

public async Task<IActionResult> OnGetLoadMoreAsync(
    string cursor, SortColumn column, SortDirection direction)
{
    var decoded = CursorCodec.Decode(cursor);
    var (items, next) = await _paginator.GetPageAsync(decoded, column, direction, PageSize);
    return Partial("_OrdersRows",
        new OrdersRowsModel(items, next is null ? null : CursorCodec.Encode(next), column, direction));
}

Two things are worth flagging about this pattern. First, it’s why keyset pagination feels more natural than offset for modern server-rendered UIs, htmx (or HTMX-like patterns in Hotwire, Unpoly, etc.) wants to append fragments, and a cursor is exactly what you need to ask for “the next fragment.” Offset’s “page N of M” model doesn’t map as cleanly. Second, this approach is back-button safe in a way that infinite-scroll SPAs often aren’t, each cursor change is a real URL, and the browser history works.

When to actually use offset

The boring section that makes the rest of the post defensible. Be specific:

  • Small tables. Under ~50K rows, the OFFSET scan cost is microseconds. Indexing for keyset is over-engineering.
  • Admin tools that need “jump to page 47.” There is no keyset equivalent. If the UX genuinely requires page numbers and total counts, offset is the answer.
  • Mostly-static data. Reporting tables, configuration data and historical archives. The concurrency argument doesn’t apply.
  • Highly dynamic sorts on moderate-sized tables. If you have twelve sort options and the table is 100K rows, the index storage and write amplification may exceed the perf gain. Run the numbers; don’t assume.
  • Hybrid setups. Some teams use offset for the visible page-number UI on admin screens and keyset for the API endpoints powering infinite-scroll feeds. Same data, two access patterns.

The decision rule, restated: keyset when the table is large AND write-heavy AND user-facing. Anything else, default to offset and revisit if you hit a real problem.

Closing

The first post made a case. The LinkedIn comments made it a better case. The honest version is: keyset pagination is the right tool for a specific shape of problem, large, hot, user-facing tables, and the cost of supporting sortable grids with it is real, paid mostly in index storage and write amplification rather than query code. For the wrong shape of the problem, the offset is simpler and finer.

If you take one thing from this post, take this: every sortable column is an index. Decide which columns are actually worth sorting by, index those, and use keyset. The decision about what’s “actually worth sorting by” is a product question, not a database one, and asking it is usually more valuable than the pagination technique you eventually pick.

Thanks to the readers on LinkedIn whose feedback pushed this post into existence.

The post Pagination in EF Core, Continued: Sortable Grids, htmx, and the Indexing Cost first appeared on Chris Woody Woodruff | Fractional Architect.

Read the whole story
alvinashcraft
2 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Introducing Command Line, and the new rules for builders

1 Share

Welcome to Command Line, a new blog where we’ll share what Microsoft builds, how our technical teams operate, and what we learn along the way. Build 2026 felt like the right time to roll this out, as we bring together engineering leaders from around the world to dive deep on building, deploying, and operating scalable AI systems. For those on the ground in San Francisco, you’ll notice that the vibe has shifted along with the locale. And that seems only fitting since the entire SDLC has changed dramatically, too. 

To kick things off officially on Command Line, I thought I’d share some of the things we’ve learned about building in the agentic AI era. Things are evolving quickly, and the old rules no longer apply. Manual review processes are breaking under a flood of PRs that our workflows weren’t designed to accommodate. Build time iteration is being met with runtime learning loops as agents improve post-deployment. And the focus is shifting from shipping code to orchestrating systems. 

> Things are evolving quickly, and the old rules no longer apply.

This is more than a productivity boost. It’s an entirely different relationship with code, tools, and decision-making. Throw out the old playbook. We need to develop a new set of rules for builders. 

Here are 10 things that feel important and true today. Time will tell how durable they prove to be. We’re in a time of seismic disruption, so we all need to constantly challenge our assumptions.  

1. Build agent-first by default 

As you develop your proficiency with AI tools, you’ll probably find yourself reaching for the Copilot CLI in GitHub or agent mode in VS Code more often than not. Many senior engineers on our own teams and across the industry no longer write code by hand, and even small tweaks are made via agents when it’s more efficient. 

2. Context and skills are your most important asset 

When you first start using an agent in your repo, you’ll notice long sessions with higher failure rates. Start by prompting the agent to populate the knowledge base of Markdown files about your repo, verify the output to ensure correctness, and then set up a continuous improvement agent so that knowledge base memory is updated after each agent session. Things start to compound rapidly. 

If you’re doing something repeatedly with an agent, wrap it into a reusable skill and share it. Team skills compound the same way code libraries do. If the same agent failure shows up twice, promote the correction into a reusable skill, test, eval, prompt, or workflow with a clear trigger. 

3. Plans are the real work 

When you invest in a good plan, the agent can often one-shot the implementation. Shift your energy from typing out code to shaping clear, scoped roadmaps. Human judgment lives in the plan. Execution runs on autopilot. 

4. Prototypes replace detailed PRDs 

Learning by doing should become the default. Experiment with live demos and prototypes to establish ground truth and guide your decisions before you commit to building. Think demos, not memos. 

5. Taste, not time, is the crucial limited resource 

When building is cheap, the discipline of deciding what’s worth building becomes more critical, not less. Product judgment and prioritization are the highest-leverage skills on the team. Additionally, with near-zero cost to prototype, deciding what to build now includes seeing concrete options upfront. 

6. Tackle the important but overlooked 

AI-forward velocity reclaims bandwidth for critical, high-value engineering debt and operational tasks that usually get pushed aside. That includes finding and fixing high-value sentry errors, repairing broken telemetry dashboards, running sentiment analysis on dogfooding feedback, and operationalizing more rigor in your data quality. 

7. Tests are your safety net 

At high velocity, good test coverage is what prevents you from shipping regressions. Invest in test quality the same way you invest in feature velocity. 

8. Don’t let code review become a bottleneck 

When small teams can ship hundreds of PRs every month, staying close to the codebase requires deliberate effort. Start using and trusting agentic code review tools like CCR, shifting first-pass code reviews to agents, and keeping humans in the loop for architectural oversight. 

9. Everything’s changing, not just code 

Build pipelines, verification, triage, planning, and team rituals all need to evolve. Longer shipping cycles gave you more time to uncover bugs. Shorter shipping cycles and a higher pace of code turnover decrease that buffer. As AI-assisted PR volume increases, you need automated, fast quality gates to keep up. 

10. Code is disposable 

Don’t be afraid to throw code away or rewrite it. For well-bounded features, the spec might become the durable artifact. And because code is disposable, you can be brutally honest in review and ditch what doesn’t serve the product. Embrace an egoless culture. 

> Taste should be the sharpest tool in your arsenal.

Bonus: Another word on taste 

In the agentic AI era, taste is the ultimate differentiator and should be the sharpest tool in your arsenal. But don’t just set it and forget it. Keep coming back and feeding the flywheel. Human taste can be captured once in curated examples, then enforced continuously across every agent trajectory. The compounding improvement loop means that as you give feedback, the bar keeps rising. 

That’s how you get high-quality code without humans writing every line. 

The post Introducing Command Line, and the new rules for builders appeared first on Command Line.

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