Show HN: Simple modenized .NET NuGet server reached RC

github.com

32 points by kekyo a day ago

A simple .NET NuGet server implementation built on Node.js that provides essential NuGet v3 API endpoints.

Key Features:

* Easy setup, run NuGet server in 10 seconds! * NuGet V3 API compatibility: Support for modern NuGet client operations * No need database management: Store package file and nuspecs into filesystem directly, feel free any database managements * Package publish: Flexible client to upload .nupkg files via HTTP POST using cURL and others * Basic authentication: Setup authentication for publish and general access when you want it * Reverse proxy support: Configurable trusted reverse proxy handling for proper URL resolution * Modern Web UI with enhanced features. * Package importer: Included package importer from existing NuGet server * Docker image available

shashasha2 a day ago

> A simple NuGet server implementation built on Node.js that provides essential NuGet v3 API endpoints

Why not build on .NET ?

  • mhh__ a day ago

    Maybe there's a lesson there. It's quite difficult to be spontaneous in dotnet (i'm not just being snippy I can immediately tell a story in my head about starting doing this in F# or C# and then bailing and doing it in an hour in a different language)

    • mrsmrtss a day ago

      Sorry, but there is absolutely nothing you gain with Node.js here in server side at least, it's clearly inferior choice for this job. You loose performance, type safety and in about two weeks there are hundreds of security issues found in your dependencies etc. Looking at the code, there are also clear security red flags for me and also the error handling is not to my taste, but that is not related to the tech. Maybe he wanted to use same language for the backe-end and front-end, but I think it's not a good argument here.

      • mhh__ a day ago

        There are affordances in technology...

        dotnet is quite nice at scale but I find it actively repellent to start new projects in when it involves touching anything vaguely DI adjacent. Microsoft have no taste in designing these libraries at all

      • banashark a day ago

        I've worked with dotnet and node for a while now (15 years of experience, with roughly half in each, and work at a company that is heavily invested in both stacks).

        I've had the opportunity to interview engineers switching to my team that have come from both backgrounds (a node engineer switching to my dotnet team, a dotnet engineer switching to my node team).

        Dotnet has plenty of advantages over node, which I'm sure you're familiar with based on the perspective of your comment, but there have been some interesting learnings when having folks from dotnet teams come over to node teams that might interest you:

        * Agility in the small

        Relevant to the featured framework of the OP, if I want to create an executable with node/bun, it's _very_ fast to get started. I can create a native executing "hello world" with 2 commands: `bun init && bun build ./index.ts --compile --outfile mycli`. This results in a 56MB[1] executable.

        _The below is incorrect, dotnet can publish single file executables as well without needing to worry about AOT library compatibility_

        ~~Getting a NAOT executable with C# isn't too much extra work either, _however_ that's where the iteration speed tanks. With node/bun I can add whatever libraries I want and don't really have to think about "is this AOT compatible?" or "are the accompanying libraries that this library goes with AOT compatible, or do I need to select a different library?". I've seen some momentum starting up to make things a bit more NAOT friendly, but it's a far cry from how effortless node/bun seem in comparison.~~

        * The default stack is more modular

        This is actually in my perspective also a con. Dotnet comes with a ton builtin, which is excellent, however what I've experienced and had corroborated by other dotnet engineers is that what is builtin to the framework often times is _just enough_ _not_ what is needed, that they need to seek out an external library. Although the modular approach has its own downsides, it means that using an integrating separate modules is often more of a trodden path than with dotnet. An example here is dotnet identity, which while an excellent library (I think it's actually underrated in some ways) often isn't enough to cover the need for things like SAML SSO that are fairly common in enterprise environments as table-stakes nowadays. With node, perhaps you just plugin better-auth which has it by default. Or, your authentication library probably has simple documented extension points, and someone has implemented it already.

        I think the distinction here is that in dotnet I tend to do more implementation vs in node I tend to do more api gluing together. There are tradeoffs in either direction.

        * It's more simple to debug libraries

        One of the benefits of node is that if a library appears to have a bug, I can just go tweak the file in my `node_modules` and reload and see if it's fixed. Stack traces also tend to be much more manageable compared to aspnetcore framework stack traces (it's not spring, but it's not small either), so the time-to-finding-out-the-path-to-a-library-function-getting-hit (and being able to reason about it) is often more quick and requires less context within my head to be maintained.

        * A thriving community of open source projects and blog posters

        Quantity is not quality, but often times when I hit a path in dotnet that doesn't seem written about much (other than perhaps a outdated project on GitHub), I'll see "I wonder how folks are doing this in java or node" where I'll find much more modern and lively discussion on topics.

        Microsoft itself does an excellent job of communicating about the projects they're focused on (example: aspire), but they haven't built the same type of community that can support other amazing, but under recognized libraries that they don't have the time to shine the spotlight on (TPL dataflow, etc).

        ----

        All this being said, I think that dotnet really has a more solid foundation. Avalonia exists and is probably the best that the node ecosystem has had yet in an all-in-one server-side framework, but there is a ton of scope that isn't well covered by it or other libraries (first thing that comes to mind is data redaction, but there are other things) and EF Core, while missing lots of features still (glad that left joins are actually coming as first-class lol) is still miles ahead of ORMs in just about any ecosystem (coming from someone who often prefers raw sql).

        This is just info to help provide another perspective.

        [1] While I agree that 56MB is insane for a hello world in theory, in practice the size of executables has never proven an issue. Devs have tons of disk space and so these things don't even make a dent.

        • seabrookmx a day ago

          Dotnet allows you to make stand-alone builds without AOT compilation as well. Like with bun, it simply bundles the JIT and you get a large executable. The command looks like `dotnet publish -r linux-x64 --self-contained true` (substitute your platform obviously).

          • banashark a day ago

            Ah I had completely forgotten about that with all of the AOT stuff I've been watching. That's a great point.

        • to11mtm 3 hours ago

          > EF Core, while missing lots of features still (glad that left joins are actually coming as first-class lol) is still miles ahead of ORMs in just about any ecosystem (coming from someone who often prefers raw sql).

          If you often prefer raw SQL, give linq2db a try. [0]

          It's not a full blown ORM like EF Core, rather it's a LINQ->SQL DSL with a lot of nice features. Left joins have been first class for years (Heck there's also a -very- explicit .Join method that takes an enum for the join type!), same with Bulk Update (EF only got that in v7 or v8 IIRC) and it's bulk insert is stupidly fast.

          Oh and it has CTE support (including recursive!) built in. Built in InsertOrUpdate support that lets you give different expressions for insert vs update (including passing the existing item into the update expression so you can do things like increment a counter or append to a string) [1]. Oh it's also got MERGE support if you know it's sane to use for your case... (I'm not a fan of MERGE)

          Also I kinda like the extension syntax better, if you want to give a method call in LINQ a specific SQL translation, it's just 1 or more attributes on the method itself. [2] EF Core seems to need more ceremony for this last I checked.

          Akka.NET is using it for their SQL persistence plugins now, since it's 'direct' enough and unlike dapper there is minimal need to maintain DB specific queries/code.

          FWIW you can also use it 'on top of' EF Core via it's shim package, i.e. it can work alongside EF Core with your existing models/code but when you need to do something 'fancy' switch to it (And the ceremony is just one line per DbContext in your DI.) It's been really helpful at my current shop when we have nasty^nasty queries that EF Core just plain gives up on translating.

          Apologies for gushing, it's my favorite library and it's been game changer at every shop I've been at.

          > Quantity is not quality, but often times when I hit a path in dotnet that doesn't seem written about much (other than perhaps a outdated project on GitHub), I'll see "I wonder how folks are doing this in java or node" where I'll find much more modern and lively discussion on topics.

          But hey if you need an EF Core ASP.NET WebAPI tutorial you are spoiled for choice!

          Yeah it's a challenge to find prior examples of things in .NET and historically you'll often be told 'not to' without a luck or a 'good reason'. It's caused some stagnation (see prior tongue-in-cheek comment) as far as innovation however there's lots of interesting stuff out there. If you find the right circles you will be able to glean lots of good knowledge but it takes more sleuthing.

          On the plus side, LLMs seem to be pretty good at 'translating' concepts from other languages into C#, I've been surprised at what Copilot can spit out even with obscure libraries so long as you have an even half-decent instruction prompt.

          > Microsoft itself does an excellent job of communicating about the projects they're focused on (example: aspire), but they haven't built the same type of community that can support other amazing, but under recognized libraries that they don't have the time to shine the spotlight on (TPL dataflow, etc).

          So much cool stuff! Like the Critter stack (Marten/Wolverine, AFAIK they actually use TPL as their base for things!), The aforementioned Akka.NET project (I may be biased but IMO Akka Streams has way more batteries included than Orleans Streams and even TPL), also, anything Cysharp puts out (They are a game development shop that does .NET, very slick purpose-specific libraries, also since they target Unity most of their stuff can target FW if you need it to.)

          [0] - https://github.com/linq2db/linq2db

          [1] - Will admit that I only really trust this in Postgres and SQLite, as those have specific syntax and don't reach for MERGE, but if those are your targets it is handy!

          [2] - I say 1 or more because if you are targeting multiple DB languages and the SQL needed is different for each, you'll need to have attributes for each snowflake case. But if whatever you're doing works on all DBs or you only care about one DB language, you just need one.

        • mhh__ a day ago

          Yes I find the modularity to be a huge mistake (for a certain definition of modularity obviously). If nothing else the quality of documentation seems to drop off a cliff.

          Maybe I'm just going mad but it seems like simple OIDC integration work is an utter pain.

          And the database point is a good one. There doesn't seem to be any innovation in ideology or design the dotnet ecosystem along these lines.

oaiey a day ago

Simple question: why code it in nodejs if .net core is more than capable of running it?

  • kid64 a day ago

    Because that's how Claude decided to handle it.

  • Kwpolska a day ago

    Packaging tools for language/ecosystem X written in another language Y are always a red flag. They had to reinvent a bunch of wheels, such as parsing metadata, and they probably did it badly.

    See also: uv.

    • seabrookmx a day ago

      Except uv is by far the best UX for Python package management out there. There's a reason they chose Rust to write this tool.

      The same goes for typing.. mypy (written in Python, and contributed to by Guido himself) performed so poorly that they had to invent a bespoke compiler for it (mypyc). The other options written in Rust or node are much more performant.

      Another example: the golang port of the Typescript compiler.

      I agree with the take it's odd to write a nuget server in node, but the comparison to uv isn't fair. There's concrete reasons to choose a more performant language for the task.

    • loic-sharma a day ago

      FWIW, the NuGet package format and the v3 server protocol are fairly simple and well documented.

    • oaiey a day ago

      And so unnecessary. .NET is perfectly fine for that.

    • whatevaa 19 hours ago

      UV is different because python performance is dogshit when actual processing is involved. Most fast Python stuff is in C extensions so Rust is no surprise here.

      • Kwpolska 7 hours ago

        It would make a lot of sense to do the slow parts in C or Rust. But the only significant slow operation in a package manager is dependency resolution.

mandeepj a day ago

> Package importer: Included package importer from existing NuGet server

Any idea how much hard drive storage space would be needed?

  • loic-sharma a day ago

    If you import all packages on nuget.org? You’re likely looking at terabytes of data.

    The import tooling can be used to migrate off another NuGet server implementation.