When you're doing development, you can generally use `nix-shell` to install all the pre-requisite tools. If you wanted to compile GNU hello, for example, you'd do:

$ nix-shell -A hello

Which will populate a temporary shell with everything you need to compile GNU hello. Then you can just do `./configure` and `make` like usual, normally. If you know an explicit list of dependencies, you can do that too, e.g. `nix-shell -p libxml2 bison flex pkg-config`, for example. Then run `make` and run `./bin/foobar`, or whatever your application is.

This is OK for development cycles (`make && make test`, things like that) but not for the long term. Most of the time incremental development works just fine this way, though, especially for software you're writing or developing yourself. You just run your commands inside a `nix-shell` instead.

If you want to use a Git repository for something, most of the time you can just 'override' a packages source code input to a new version. In Nix, even source code is actually an 'input' (a parameter) to a build script (a function), so you can just provide a new copy of the source code (pass a different parameter to the function) and rebuild. Of course, someones Git repository may have changed in ways that make the old build script incompatible. You can similarly override/update the build script, and there are a number of mechanisms to do this.

> My concern is that it would be more difficult to install software that doesn't have a nix package built (in particular, from git repo trunks)

This is true and in reality most Nix users are package authors. You will probably find things that are not packaged and you will have to author them. Occasionally, a package may not have some feature enabled (maintainers generally decide these things on their own when it comes to optional features), so you may have to fix it.

Updating/custom source code versions isn't as much of a problem though. Once the Nix expression for some software is authored just pointing/updating the source repository is normally enough to do it.

> and also more difficult to have confidence that the software I write would work on other Linux distros

IME, if your software can work correctly on NixOS with little modification (or extremely perverted build scripts), it will almost certainly work fine anywhere else. In particular as long as your build system obeys "standard rules" like supporting PREFIX and respecting things like `pkg-config`, not hardcoding binary paths everywhere but detecting them, it will normally work just fine. cmake, autotools, pypi, etc all have pretty usable solutions for the extremely common cases. Nix can often quickly unveil assumptions in your build step that would previously be masked (for example, I cannot count the amount of READMEs that have 'apt-get' instructions for build prerequisites, which do not actually account for all the necessary dependencies.)

Realistically I have authored dozens of packages and the ones that cause the most pain are ones that have complex, bespoke build systems with a lot of assumptions built in, or that don't actually specify all the dependencies they think they do, and silently get things wrong. Think packages like OpenJDK, Mono, any web browser, etc etc. Other things occasionally require some bespoke patching to get cleaner integration, even if the build system itself is otherwise nice enough (such as PostgreSQL or Linux itself.)

> In practice NixOS users find these to be significant issues? How do you deal with them?

They can be annoying, and I would say writing build expressions is sometimes a bit more difficult than I'd like -- but not enough to outweigh the actual advantages, which are otherwise tremendous.

Normally I just author packages and submit them upstream for cases like this. In the case where a fix for some issue seems reasonable to upstream I just submit it upstream like a traditional maintainer. Not everything falls into this category, though, so, like any maintainer, you might be on the hook for it.