Welcome to the Umbraco Community!

The Umbraco Community is at the heart of the Umbraco ecosystem. It’s built on people coming together to share ideas, help each other, and make Umbraco better every day.

Come see how the Community stays connected, what makes it such a great place to be, and how you can join in and get involved. We always have room for more people to join!

MVP Summit audience.jpg 54610954933_1fd227623f_o (1).jpg Panel speaking in mics at umbraco event Person looking at laptop 52993341606_3b3a6a6991_o.jpg 2025 Group picture 1740139582170.jpg IMG_4217.jpg IMG20251030182101.jpg 2025 Community Teams day at Umbraco HQ DSC04687.jpg DSC05663.jpg MVP getting high five on stage MVPs speaking at MVP Summit 2 MVP waving at MVP Summit MVPs showing off awards IMG20251106141733.jpg 20251204_173423.jpg b6f67a24-17ea-4a21-bc55-65eca97d86ac.jpeg Codegarden 2023 Business Summit - people talking.jpg People high five'ing at Codegarden.jpg Boat ride 2025 Codegarden runners running

Get involved in the community

There's so many ways to get involved in the Umbraco community. 

A person looking into his laptop surrounded by people and light

New here? Welcome! We have a complete newcomer's guide to Umbraco and the Umbraco Community waiting for you.

A woman concentrating and looking down

No matter your interests, skills and time availability, there’s a way for you to participate in the Umbraco community. 

Two people high five'ing

Umbraco Meetups are a great way to engage with the Umbraco community and meet other like-minded people.

See what's happening

Join a meetup or an event near you - see all upcoming Umbraco events here

Blog posts from the Umbraco Community

Explore the latest blog posts from our community. Want to add your future blog posts to the list? Submit it here!

Smidge 5 is out

Smidge 5 is out Smidge 5.0.0 is out on NuGet! It's been about a year since the last release, so sorry 'bout that 😅. This one turned into a proper major version rather than another collection of small fixes: Smidge is now on .NET 10, NUglify is the only minifier, the MVC dependency is gone, the package structure is simpler, and a few long-running production bugs have finally been tracked down properly. The full release notes have every detail. This is the story behind the parts that matter most. One minifier instead of three Smidge has historically shipped with its own hand-rolled JavaScript and CSS minifiers, JsMinifier and CssMinifier, while also offering NUglify through the separate Smidge.Nuglify package. That made sense when those minifiers were first added, but over time it meant maintaining two different approaches to the same job. The built-in implementations had their own edge cases and bugs, while NUglify was already the better maintained and more capable option. In v5 the old JSMin and CSSMin implementations are gone. NUglify is now included directly in the main Smidge package and is used automatically by the normal AddSmidge() and UseSmidge() setup. The separate Smidge.Nuglify package, along with AddSmidgeNuglify() and UseSmidgeNuglify(), is no longer needed. This is a breaking change, but it's also a much simpler default. There is one minification pipeline, one set of behaviour to test, and source maps work without having to opt into another package. .NET 10 and no more MVC dependency Smidge now targets .NET 10. The old MVC controllers used to serve bundle, composite-file and source-map requests. Those have been replaced with lightweight minimal API endpoints, with the old action-filter behaviour moved into endpoint filters. That removes the MVC dependency entirely. If you're using Smidge in a small ASP.NET Core app you no longer need to pull MVC into the application just to serve a CSS or JavaScript bundle. As part of that work, the old Smidge.Core project has also been folded into Smidge. There isn't much value in making consumers understand the internal package split, and having the public surface spread across assemblies made the dependency graph harder to follow than it needed to be. The practical result is fewer packages, fewer setup methods and less framework machinery underneath it all. The random bundle crash was actually a race condition There have been a couple of reports over the years of Smidge suddenly throwing a NullReferenceException from BundleFileSetGenerator.ValidateFile. The frustrating part was that it only seemed to happen in production, often after an application had been running for a while, and recycling the app pool would make it disappear. The immediate symptom was a null file entry inside a bundle, but there was no obvious path that intentionally added one. I added defensive checks so a bad entry could be logged and skipped instead of taking down the entire bundle response, but that still didn't explain how it got there. The missing clue came from somebody who found that wrapping their view-based bundle registration in an application-level lock made the problem go away. That pointed at the real problem. BundleManager is a singleton and its bundle dictionary was thread-safe, but each bundle stored its files in a normal List<IWebFile>. View-based declarations can run from multiple concurrent requests, which meant multiple threads could call List<T>.Add on the same list at the same time. List<T> doesn't support concurrent writers, and if two additions collided during an internal resize the list could lose entries or end up with null slots. It wasn't the cache buster, app pool idle state or a missing source file. It was memory corruption inside a concurrently mutated list. Bundle.Files is now backed by an immutable list and updated with ImmutableInterlocked.Update. Reads get a complete, unchanging snapshot with no locking cost, and concurrent writers use a compare-and-swap loop rather than corrupting the same backing array. There are also defensive null checks at bundle creation and file-set generation, because a bad input still shouldn't turn into a broken page. A concurrency test that registers files from 50 tasks at once reliably lost entries against the old implementation. With the new implementation every file is present and there are no nulls. This is probably the most important fix in the release even if it's not the flashiest one. Missing cache files now return 404 The other production hardening work is around stale or invalid bundle URLs. Composite bundle URLs contain references to already-processed cache files. If the cache was cleared, an in-memory cache disappeared after an application restart, or somebody deliberately requested a made-up file hash, Smidge used to call a throwing file lookup. That surfaced as a 500 and could be triggered repeatedly, which made it a fairly easy denial-of-service path. The HTTP-facing composite and source-map handlers now use non-throwing lookups. If a requested cache file isn't there, Smidge returns a normal 404 instead of throwing. Internal invariants still throw where they should - a source file configured in a real bundle disappearing is different from an arbitrary client asking for a stale cache path. The same work fixed an older source-map issue where an unexpected sourceMappingURL request could fail with Could not parse ... as a valid smidge path. Invalid or missing source-map requests now just return 404, which is what the browser expects anyway. Globs and directory bundles There are a couple of smaller file-matching fixes that are worth calling out. Pointing a bundle at a bare directory used to expand it to *.*. That could pull generated files such as .js.gz or .map into a JavaScript bundle and then hand binary gzip data to NUglify, which ended about as well as you'd expect. Bare directory bundles are now constrained to the bundle type, so JavaScript bundles get .js files and CSS bundles get .css files. Recursive glob patterns are supported as well: bundles.CreateCss("site", "~/assets/css/**/*.css"); They already worked for the common physical-file-provider case through .NET's built-in globbing support, but the fallback used for embedded and composite file providers didn't understand the **.css form correctly. Both **.css and **/*.css now behave consistently across providers. Breaking changes This is a major version, so there are a few things to account for when upgrading: Smidge now targets .NET 10. Smidge.Core has been merged into Smidge and the separate assembly no longer exists. Smidge.Nuglify, AddSmidgeNuglify() and UseSmidgeNuglify() are no longer needed. NUglify is built into the normal Smidge setup. The old built-in JsMinifier and CssMinifier are gone. A few old MVC handler and filter types are now internal implementation details. Bundle.Files is now IReadOnlyList<IWebFile> rather than a mutable List<IWebFile>. Use Bundle.AddFile(IWebFile) if you need to add files programmatically. For most applications the upgrade should mainly be removing the old NUglify-specific setup and package reference, then rebuilding against .NET 10. If you only used the standard AddSmidge() / UseSmidge() APIs and predefined bundles, there shouldn't be much else to change. Build and release cleanup The dependency set has been brought up to date, including the Microsoft.Extensions packages, SourceLink, xUnit, the test SDK and Moq. I've also replaced GitVersion with MinVer. The version now comes directly from the Git tag: normal builds produce a 5.0.0-ci.<height> prerelease version and the v5.0.0 tag produces exactly 5.0.0. It's considerably less machinery for what Smidge needs. Give it a go Smidge 5.0.0 is available on NuGet, and the source and full release notes are on GitHub. This release took longer than it should have, but it also ended up being more substantial than I'd originally planned. The package setup is simpler, the runtime surface is smaller, and the two worst classes of production failure - corrupted bundle registrations and attacker-reachable cache misses turning into 500s - are now properly fixed rather than worked around. If you run into anything while upgrading, please open an issue. And thanks to everyone who kept reporting the weird, hard-to-reproduce failures over the years. Those are never the fun ones to investigate, but in this case they led to a much better fix than another null check 🙂

by Shanon Thompson (Deminick)

Retiring Named Pipes: A Simpler Fix for Dev Port Conflicts

Back in February I wrote about solving dev-server port conflicts with HTTP over named pipes. The short version: I run a lot of parallel Claude Code...

by Matt Brailsford

Building a QR-Code Walking Route App with Umbraco, Next.js and AI

.I built a QR-code walking route app using Umbraco 18, Next.js and an AI coding agent. In this post I explain the content model, the headless setup, how MCP was used to configure Umbraco, and which rules helped keep the AI-generated implementation co...

by Johan Reitsma

Get in contact with us