hear what the community is talking about

Community Blogs

We’ve gathered blog posts from across the internet to highlight the many voices that make up our community. Powered by Umbraco, this space brings together diverse stories, ideas, and perspectives in one easy‑to‑explore hub. Dive in and discover what the community is creating, sharing, and talking about.

Want to add your future blog posts to the list? Submit it here!

Umbraco

Umbraco 2-way relations - Umbraco Features You Didn't Know You Needed

Relations in Umbraco: asking the question your picker can't answer You've probably used a Content Picker (or a Multinode Treepicker) to wire content together. A page picks a banner, a landing page picks a set of related articles, a policy picks the older policy it replaces. That gives you one direction for free: open the page, and you can see exactly what it points at. But pickers only answer one question. "What does this page use?" is easy. "What uses this?" is not. The picker property lives on the node that did the picking, not on the node that got picked. If you want to go the other way, your only option is make the pages hierarchical or to loop over every piece of content in the tree and check whether its picker field happens to mention the node you care about. That's exactly the gap Umbraco's Relations are for. A Relation is a first-class, queryable link between two entities that you can walk in either direction via IRelationService: GetByParentId for "what does this point at", GetByChildId for "what points at this". This post walks through a small example project that uses a Relation to answer a question a picker alone can't. The scenario: policies that supersede each other Imagine a "Policy Page" doctype. Editors write a new policy, and pick (via a normal Multinode Treepicker) which older policy or policies it supersedes. That's a completely standard one-way relationship: new policy → picks → old policy. The picker answers "which policies does this one supersede" perfectly well. What it can't answer is the question an editor actually asks when they land on an old policy page: "Has this been superseded, and by what?" Nothing on that old policy's own data points back to the newer one — the pick lives entirely on the other node. Short of scanning every Policy Page in the site for one whose supersedes field happens to mention this node's ID, there's no way to answer it. Why not just use Umbraco's built-in "Related Document" relation? Umbraco ships a built-in relation type for exactly this kind of document-to-document link, aliased umbDocument. It would technically work — except it's a single shared, undifferentiated bucket. Anything in Umbraco (media picker usages, link pickers, whatever else) can write a generic document-to-document reference into it, so a reverse lookup on umbDocument can't reliably tell you "which policy superseded this one" versus any other unrelated reference someone else recorded into the same bucket. The fix is a relation type of your own policySupersedes so a reverse lookup on that alias only ever returns the thing you actually care about. The implementation The example lives in four files. 1. The doctype and the picker. Add a "Policy Page" content type with a bodyText richtext property and a supersedes Multinode Treepicker, filtered so it can only pick other Policy Pages. This is the plain, one-way picker. Nothing special yet. 2. Syncing the picker into a Relation. PolicySupersedesRelationSyncHandler listens for ContentSavedNotification. Every time a Policy Page is saved, it wipes out whatever relations already exist for that node under the policySupersedes alias and rebuilds them from whatever's currently picked: public void Handle(ContentSavedNotification notification) { foreach (IContent content in notification.SavedEntities) { if (content.ContentType.Alias == PolicyPageContentTypeAlias) { SyncSupersedesRelations(content); } } } private void SyncSupersedesRelations(IContent newPolicy) { IRelationType relationType = _relationService.GetRelationTypeByAlias(ExampleConstants.RelationTypeAlias) ?? CreateRelationType(); foreach (IRelation existingRelation in _relationService.GetByParentId(newPolicy.Id, ExampleConstants.RelationTypeAlias)) { _relationService.Delete(existingRelation); } foreach (int supersededPolicyId in GetPickedContentIds(newPolicy)) { var relation = new Relation(newPolicy.Id, supersededPolicyId, relationType) { Comment = $"Marked as superseded on {DateTime.UtcNow:u}", }; _relationService.Save(relation); } } As shown above, you can also add a comment to a relation, which we use to store additional information on when the policy was superseded in our example, which can then be shown again on the Policy page. The relation type itself is created on demand as non-bidirectional, Document-to-Document, and importantly isDependency: true: private IRelationType CreateRelationType() { var relationType = new RelationType( "Policy Supersedes", ExampleConstants.RelationTypeAlias, isBidrectional: false, parentObjectType: Constants.ObjectTypes.Document, childObjectType: Constants.ObjectTypes.Document, isDependency: true, key: null); _relationService.Save(relationType); return relationType; } 3. Wiring it up. Add the notification handler with the standard IComposer boilerplate, nothing Relations-specific. 4. Reading both directions in the view. This is where the payoff shows up. policyPage.cshtml reads the picker property directly for the forward direction, and calls RelationService.GetByChildId for the reverse direction, the direction the picker alone could never give you: var supersededByRelations = RelationService.GetByChildId(Model.Id, ExampleConstants.RelationTypeAlias); @if (supersededByRelations.Any()) { <div style="border: 2px solid red; padding: 1em; margin-bottom: 1em;"> <strong>This policy has been superseded.</strong> <ul> @foreach (var relation in supersededByRelations) { var newerPolicy = ContentQuery.Content(relation.ParentId); if (newerPolicy is not null) { <li> Replaced by <a href="@newerPolicy.Url()">@newerPolicy.Name</a> <br /> <small>@relation.Comment</small> </li> } } </ul> </div> } Open an old policy that's been superseded, and the page now knows it without ever scanning the rest of the tree. The other payoff: you can't delete a still-referenced policy without a warning Setting IsDependency = true on the relation type isn't just documentation, it plugs straight into Umbraco's own dependency checks. Try to delete or unpublish a policy that's still marked as superseded by another one, and the backoffice will warn you it's in use, the same way it would for a media item still referenced by a Content Picker elsewhere. This is the practical version of "what if you need to delete a shared component, but three pages still reference it": with a plain picker, deleting the referenced item is silent and the reference just breaks. With a proper Relation, Umbraco already knows something depends on it and stops you. When to reach for this A picker is enough when you only ever need to ask "what does this content point at", the normal, forward direction. The built-in "Related Document" relation is fine for generic, low-stakes cross-references where you don't care about precision on the reverse lookup. A custom relation type is worth the extra notification-handler code when you need a reverse lookup you can trust "what points at me" and/or you want deletion/unpublish safety for content that's still depended on. Pickers tell you what a page uses. Relations are what let you ask the question in the other direction.

by Bernadet Goey

Announcing the new ProWorks Umbraco Media Audit package!

One of the things I've been asked for by clients more often than I'd expect in the last few months is to help them audit all their media so that they can clean out everything they're not using. The good news is that with access to a database and Claude, writing a little reusable python script to scrape everything was exceptionally easy. But by the third request I'd decided maybe that rather than doing this for my clients I could give them the autonomy and flexibility to do this by themselves on demand. After all, it's a waste of their time and budget to need a developer to audit their media whenever they're wanting to clean it up. The benefit of this package is it gives your content editors the autonomy to audit and clean up their own media on their own schedule whenever they want! So with this, I present to you the new ProWorks Umbraco Media Audit package that I've released for Umbraco 17 and 18! This tidy little package adds a dashboard into your media section where you can run an audit on all of your media, discover what's in use and what isn't all in one location without having to click through item after item. There's some caveats of course - the audit is based on Umbraco's own reference tracking, so the main list only knows about media that's referenced with a picker. If a client pasted a URL manually somewhere, it can still show up as unused. The good news is that before anything is actually deleted, the Media Audit does a second scan through all your content for the item's ID, file path, or file name, and skips anything it finds. If you're linking to an item in an e-mail marketing campaign though, there's still no way for the Media Audit to tell. So it's important that human eyes look at these items when determining if they're still relevant, and getting detail on an item by item basis is very easy to do. And once an admin-only user has determined none of the media is in use, they can mark them all for deletion and move them into the recycle bin. If they're really content all is well then there's even a purge button to clear the recycle bin and remove the items from disk! Every delete and purge is also recorded in a deletion log, so you can always see who removed what, when, and how much space it freed up. Sometimes files end up in your media folder without a matching media item in Umbraco - think old migrations or files copied straight onto the server. The new Scan Disk Media button finds those orphaned files, lists their size and last modified date, and lets an admin export or delete them. Each file gets re-checked right before it's deleted, just to be safe! To get started, install it with dotnet add package ProWorks.Umbraco.MediaAudit. Version 1.x is for Umbraco 17 and version 18.x is for Umbraco 18. We have a few features that we want to add in the future: Field auditing - do you have your alt text or captions filled out? We'd like to make this "plug and play" so you can add any fields that you want and the tool will check if they're empty. Integrating the above with Umbraco AI - if a field is empty, fill it in with Umbraco AI's integrations to read media files and write alt text. Display a thumbnail of the item in the dashboard (if it's an image) to help with visual recognition Check if images don't have crops selected or set Show media that's hard-linked in rich text as "in use" in the main audit list, not just at delete time - thanks to JLD for the suggestion! Are there any features that you'd love to see? Let us know! Version history October 15, 2026 (18.1.0 / 1.1.0): Added Scan Disk Media and fixed audits getting stuck on "Running" under IIS. September 9, 2026 (18.0.2 / 1.0.3): Fixed deletion log entries being truncated on SQL Server. September 8, 2026 (18.0.1 / 1.0.2): Fixed a startup failure on SQL Server. September 2, 2026 (18.0.0): Released the Umbraco v18 version! August 28, 2026 (1.0): Launched for Umbraco 17.

by Proworks

Quick Tip: Extending the Delivery API's Content Response

A quick look at how to extend Umbraco 17’s Delivery API response with content from elsewhere in the content tree, without building a custom endpoint....

by Johan Reitsma

Notify a Teams channel when you publish content, using Umbraco Automate

Use Umbraco Automate to post a notification to a Microsoft Teams channel whenever content is published, with no custom C#. A step by step walkthrough on Umbraco 17.

by Nathaniel Nunes

Why I choose Umbraco over WordPress

Umbraco and WordPress solve different problems, and after years of building on both I know which one I want to still be maintaining in five years.

by Justin Neville

Examine v4 is out

Examine v4 is out Examine v4.0.0 has been released to NuGet! It's been in beta since October 2023, so it feels great to finally have this one out the door. The headline feature is faceting, which people have been asking me about for years, along with taxonomy indexes, deep paging, and a fair amount of modernization of the codebase. What took so long The first facet commit landed in November 2022 from Nikolaj Brask-Nielsen who did the original implementation, and then Chad Currie built taxonomy index support, deep paging and a lot of the surrounding infrastructure on top of that. Between them that's well over a hundred commits of genuinely hard Lucene work, and honestly the community contributions on this release have been fantastic. After that it sat in beta across nine releases. Part of that is simply that Examine is a side project I maintain around a full time job, and nothing was broken enough in the betas to force the issue. The other part is that Examine v4 is built on Lucene.NET 4.8, which is itself still in beta, and I didn't want to ship a final release that depended on a beta of something else. So the plan was to wait for Lucene.NET 4.8 to go stable first. Lucene.NET 4.8.0-beta00001 was released in May 2017, and the last stable Lucene.NET release was 3.0.3 back in 2012, so in hindsight that was a fairly optimistic plan 😊 That's not a criticism by the way - porting Lucene to .NET is an enormous amount of work done by volunteers and the project is very much active. beta00018 shipped in June this year and the hope is for a final 4.8 release before the end of the year. In practice these betas have been running in production on a very large number of Umbraco sites for years now, so the beta label was never really the risk that it sounds like. What changed is that Umbraco needed v4. What's new in v4 Faceting is the main one. You declare facet fields in your field definitions like any other field, request facets on a query with WithFacets(...), and read them back with GetFacet(): var results = searcher.CreateQuery("content") .Field("nodeName", "product") .WithFacets(facets => facets.FacetString("category")) .Execute(); foreach (var value in results.GetFacet("category")!) { Console.WriteLine($"{value.Label}: {value.Value}"); } There are facet types for full text, numerics, dates and ranges, and each has a taxonomy variant. Being able to do this natively in Examine, rather than dropping down to Lucene yourself, is the bit I'm most pleased about in this release. The rest of it: Taxonomy indexes - a sidecar index enabled with UseTaxonomyIndex, which gives you hierarchical facets and faster faceting generally. This started out as a separate index type and ended up merged into LuceneIndex, which is a much better place for it. Deep paging - SearchAfterOptions lets you page a long way into a result set without Lucene having to materialize everything up to your offset. It works with faceted queries too. Boost factors and phrase queries - WithBoost() on individual search values, and a proper Phrase() instead of the old escaped value approach. Nullable reference types throughout, with warnings as errors, so every public API is annotated. You'll likely get some new warnings when you upgrade, all of which were true before, you just couldn't see them. .NET 8, 9 and 10. .NET 6 support is gone. The replicator has also had a lot of work done to it. Taxonomy replication is handled properly, transient lock failures are retried instead of thrown, and persistent commit failures now surface through IsReplicationHealthy instead of being silently swallowed. If you're running Examine on Azure App Service, or anything else with a network file system, that's the part that matters to you. There are breaking changes and they're mostly constructors. The release notes have a summary and the full API change report lists every one of them. Umbraco and the new search abstraction Umbraco HQ have been rebuilding search from the ground up in Umbraco.Cms.Search, based on the Future of Search RFC written by Bjarke Berg and Kenn Jacobsen. It's a provider based abstraction, so in principle you can put Elasticsearch, Algolia or anything else behind it. For the initial release there is one provider, and it's Examine. From the RFC: We plan to ship a single implementation of the search abstraction, which will be based on Examine to be backward compatible. Their README says it will replace the current search implementation "at the earliest starting from Umbraco v19" so I'm not going to put a date on that, but it ships as an add-on for v17 and v18 first and Examine is what sits underneath it either way. Which meant that v4 suddenly had a real consumer with real deadlines, and a beta wasn't going to cut it any more. It's a nice position to be in though - Examine has been quietly doing its job under Umbraco for years, and it's great to see it become the foundation for the new search stack too. Backwards compatibility Most of the work in the final stretch wasn't features at all, it was making sure v4 could be a drop-in replacement for v3. Examine underpins search in every Umbraco install, so telling everyone to upgrade and fix up their code isn't a realistic answer. I spent a good while on this with Kenn Jacobsen and Nikolaj Geisle at Umbraco HQ - they would run v4 against the CMS, something would break, and we'd work out whether it was a genuine bug, an API I'd removed too eagerly, or something that needed a compatibility shim. Then repeat. There was a lot of testing on both sides of this. A good example of the kind of thing that catches you out: I had removed some old positional overloads of AddExamineLuceneIndex and replaced them with optional parameters. That's source compatible, so anything recompiling against v4 is fine. But optional parameters are a compile time feature, and Umbraco's already published DLLs still had IL referencing the original method signatures, so it fell over on startup with a MissingMethodException. Source compatible, binary incompatible, and the only way to find it is to actually run it. Automating the compatibility testing Doing that verification manually over and over is pretty tedious, so I stopped doing it manually. I wrote a set of Copilot skills that live in the Examine repo and automate the whole loop - clone the downstream consumer, rewrite its Examine NuGet package references into project references pointing at my local working copy, build it, run its tests, and report back exactly what broke. There's one each for Umbraco CMS, Umbraco.Cms.Search and ExamineX, plus a compat validator agent that picks the right one and drives it. That turned "have I broken Umbraco?" from an afternoon's work into something I could run as a routine check while working on a branch. Combined with the Roslyn public API analyzer, which tracks every public member in a checked-in file and fails the build when one disappears, breaking changes had to be a deliberate decision rather than something discovered later by somebody else. If you maintain a library with downstream consumers you care about, this is honestly worth setting up. It's a lot more approachable to build than it was even a year ago, and it takes a whole category of worry off your plate. Umbraco.Cms.Search is currently pinned to 4.0.0-beta.9 and can now move to the final release. Documentation The documentation site hadn't been published since March 2023. Not for lack of anyone writing any - the publishing pipeline itself had quietly been broken for years. It only triggered on a branch nobody was pushing to, it used versions of the GitHub Pages actions that have since been removed, and it built with .NET 6, which can't compile a project targeting .NET 8 or later. So documentation kept getting written and committed and never actually went anywhere. That's all fixed now and the docs rebuild and publish automatically on every push, which means about three years of writing has gone live in one go. Faceting, taxonomy indexes, deep paging and replication are all documented, so it's well worth a look if the last version you saw was the old site. A number of the older code samples turned out to be wrong as well, including every faceting example, which called a method that doesn't exist. This time around every sample was compiled against the real v4 assemblies rather than just eyeballed, which is how those got caught. The public API change report is published there too - 246 additions, 19 changed signatures and 14 removals between v3.10.0 and v4.0.0. It's generated from the API surface files that the analyzer keeps in the repo rather than written by hand, so it's the complete picture rather than what I remembered to write down. What this means for ExamineX I've been asked this a few times now so it's worth spelling out. ExamineX is my commercial product that swaps Examine's Lucene implementation for Azure AI Search or Elasticsearch, so that you don't have to deal with file locks, index corruption and index rebuilds on Azure App Service. It has always been an implementation of the Examine abstractions rather than a fork or a competing API. That's the important part here. Umbraco Search has a provider model and its default provider talks to Examine. Examine has its own implementation model underneath that, and that's the layer ExamineX plugs into. They're two separate seams stacked on top of each other, so ExamineX continues to work under Umbraco Search without needing to be an Umbraco Search provider at all - it just replaces what sits underneath the Examine one. So the new Umbraco search stack doesn't replace ExamineX, it sits on top of the same abstraction it always has. The v4 support including faceting is already written, I just haven't cut the release yet - that's next on my list. Upgrading If you're on v3 and not using Umbraco then it should be reasonably straight forward. Retarget to net8.0 or later, rebuild, work through whatever the nullable annotations tell you, and check the API change report if you were constructing searchers or directory factories by hand. If you're on Umbraco, wait for Umbraco to pull it in rather than upgrading Examine underneath it yourself. Everything is on GitHub and issues and PRs are always welcome. Give it a go! Huge thanks to Chad, both Nikolajs and Kenn, and to everyone who ran the betas in production and told me what broke. Seventeen years in and Examine is in the best shape it's ever been, which is a pretty good feeling 🙂

by Shanon Thompson (Deminick)

Examine v4 is out

Examine v4 is out Examine v4.0.0 has been released to NuGet! It's been in beta since October 2023, so it feels great to finally have this one out the door. The headline feature is faceting, which people have been asking me about for years, along with taxonomy indexes, deep paging, and a fair amount of modernization of the codebase. What took so long The first facet commit landed in November 2022 from Nikolaj Brask-Nielsen who did the original implementation, and then Chad Currie built taxonomy index support, deep paging and a lot of the surrounding infrastructure on top of that. Between them that's well over a hundred commits of genuinely hard Lucene work, and honestly the community contributions on this release have been fantastic. After that it sat in beta across nine releases. Part of that is simply that Examine is a side project I maintain around a full time job, and nothing was broken enough in the betas to force the issue. The other part is that Examine v4 is built on Lucene.NET 4.8, which is itself still in beta, and I didn't want to ship a final release that depended on a beta of something else. So the plan was to wait for Lucene.NET 4.8 to go stable first. Lucene.NET 4.8.0-beta00001 was released in May 2017, and the last stable Lucene.NET release was 3.0.3 back in 2012, so in hindsight that was a fairly optimistic plan 😊 That's not a criticism by the way - porting Lucene to .NET is an enormous amount of work done by volunteers and the project is very much active. beta00018 shipped in June this year and the hope is for a final 4.8 release before the end of the year. In practice these betas have been running in production on a very large number of Umbraco sites for years now, so the beta label was never really the risk that it sounds like. What changed is that Umbraco needed v4. What's new in v4 Faceting is the main one. You declare facet fields in your field definitions like any other field, request facets on a query with WithFacets(...), and read them back with GetFacet(): var results = searcher.CreateQuery("content") .Field("nodeName", "product") .WithFacets(facets => facets.FacetString("category")) .Execute(); foreach (var value in results.GetFacet("category")!) { Console.WriteLine($"{value.Label}: {value.Value}"); } There are facet types for full text, numerics, dates and ranges, and each has a taxonomy variant. Being able to do this natively in Examine, rather than dropping down to Lucene yourself, is the bit I'm most pleased about in this release. The rest of it: Taxonomy indexes - a sidecar index enabled with UseTaxonomyIndex, which gives you hierarchical facets and faster faceting generally. This started out as a separate index type and ended up merged into LuceneIndex, which is a much better place for it. Deep paging - SearchAfterOptions lets you page a long way into a result set without Lucene having to materialize everything up to your offset. It works with faceted queries too. Boost factors and phrase queries - WithBoost() on individual search values, and a proper Phrase() instead of the old escaped value approach. Nullable reference types throughout, with warnings as errors, so every public API is annotated. You'll likely get some new warnings when you upgrade, all of which were true before, you just couldn't see them. .NET 8, 9 and 10. .NET 6 support is gone. The replicator has also had a lot of work done to it. Taxonomy replication is handled properly, transient lock failures are retried instead of thrown, and persistent commit failures now surface through IsReplicationHealthy instead of being silently swallowed. If you're running Examine on Azure App Service, or anything else with a network file system, that's the part that matters to you. There are breaking changes and they're mostly constructors. The release notes have a summary and the full API change report lists every one of them. Umbraco and the new search abstraction Umbraco HQ have been rebuilding search from the ground up in Umbraco.Cms.Search, based on the Future of Search RFC written by Bjarke Berg and Kenn Jacobsen. It's a provider based abstraction, so in principle you can put Elasticsearch, Algolia or anything else behind it. For the initial release there is one provider, and it's Examine. From the RFC: We plan to ship a single implementation of the search abstraction, which will be based on Examine to be backward compatible. Their README says it will replace the current search implementation "at the earliest starting from Umbraco v19" so I'm not going to put a date on that, but it ships as an add-on for v17 and v18 first and Examine is what sits underneath it either way. Which meant that v4 suddenly had a real consumer with real deadlines, and a beta wasn't going to cut it any more. It's a nice position to be in though - Examine has been quietly doing its job under Umbraco for years, and it's great to see it become the foundation for the new search stack too. Backwards compatibility Most of the work in the final stretch wasn't features at all, it was making sure v4 could be a drop-in replacement for v3. Examine underpins search in every Umbraco install, so telling everyone to upgrade and fix up their code isn't a realistic answer. I spent a good while on this with Kenn Jacobsen and Nikolaj Geisle at Umbraco HQ - they would run v4 against the CMS, something would break, and we'd work out whether it was a genuine bug, an API I'd removed too eagerly, or something that needed a compatibility shim. Then repeat. There was a lot of testing on both sides of this. A good example of the kind of thing that catches you out: I had removed some old positional overloads of AddExamineLuceneIndex and replaced them with optional parameters. That's source compatible, so anything recompiling against v4 is fine. But optional parameters are a compile time feature, and Umbraco's already published DLLs still had IL referencing the original method signatures, so it fell over on startup with a MissingMethodException. Source compatible, binary incompatible, and the only way to find it is to actually run it. Automating the compatibility testing Doing that verification manually over and over is pretty tedious, so I stopped doing it manually. I wrote a set of Copilot skills that live in the Examine repo and automate the whole loop - clone the downstream consumer, rewrite its Examine NuGet package references into project references pointing at my local working copy, build it, run its tests, and report back exactly what broke. There's one each for Umbraco CMS, Umbraco.Cms.Search and ExamineX, plus a compat validator agent that picks the right one and drives it. That turned "have I broken Umbraco?" from an afternoon's work into something I could run as a routine check while working on a branch. Combined with the Roslyn public API analyzer, which tracks every public member in a checked-in file and fails the build when one disappears, breaking changes had to be a deliberate decision rather than something discovered later by somebody else. If you maintain a library with downstream consumers you care about, this is honestly worth setting up. It's a lot more approachable to build than it was even a year ago, and it takes a whole category of worry off your plate. Umbraco.Cms.Search is currently pinned to 4.0.0-beta.9 and can now move to the final release. Documentation The documentation site hadn't been published since March 2023. Not for lack of anyone writing any - the publishing pipeline itself had quietly been broken for years. It only triggered on a branch nobody was pushing to, it used versions of the GitHub Pages actions that have since been removed, and it built with .NET 6, which can't compile a project targeting .NET 8 or later. So documentation kept getting written and committed and never actually went anywhere. That's all fixed now and the docs rebuild and publish automatically on every push, which means about three years of writing has gone live in one go. Faceting, taxonomy indexes, deep paging and replication are all documented, so it's well worth a look if the last version you saw was the old site. A number of the older code samples turned out to be wrong as well, including every faceting example, which called a method that doesn't exist. This time around every sample was compiled against the real v4 assemblies rather than just eyeballed, which is how those got caught. The public API change report is published there too - 246 additions, 19 changed signatures and 14 removals between v3.10.0 and v4.0.0. It's generated from the API surface files that the analyzer keeps in the repo rather than written by hand, so it's the complete picture rather than what I remembered to write down. What this means for ExamineX I've been asked this a few times now so it's worth spelling out. ExamineX is my commercial product that swaps Examine's Lucene implementation for Azure AI Search or Elasticsearch, so that you don't have to deal with file locks, index corruption and index rebuilds on Azure App Service. It has always been an implementation of the Examine abstractions rather than a fork or a competing API. That's the important part here. Umbraco Search has a provider model and its default provider talks to Examine. Examine has its own implementation model underneath that, and that's the layer ExamineX plugs into. They're two separate seams stacked on top of each other, so ExamineX continues to work under Umbraco Search without needing to be an Umbraco Search provider at all - it just replaces what sits underneath the Examine one. So the new Umbraco search stack doesn't replace ExamineX, it sits on top of the same abstraction it always has. The v4 support including faceting is already written, I just haven't cut the release yet - that's next on my list. Upgrading If you're on v3 and not using Umbraco then it should be reasonably straight forward. Retarget to net8.0 or later, rebuild, work through whatever the nullable annotations tell you, and check the API change report if you were constructing searchers or directory factories by hand. If you're on Umbraco, wait for Umbraco to pull it in rather than upgrading Examine underneath it yourself. Everything is on GitHub and issues and PRs are always welcome. Give it a go! Huge thanks to Chad, both Nikolajs and Kenn, and to everyone who ran the betas in production and told me what broke. Seventeen years in and Examine is in the best shape it's ever been, which is a pretty good feeling 🙂

by Shanon Thompson (Deminick)