services-flake: NixOS-like services for plain Nix flakes
NixOS-like services for Nix flakes [maintainer=@shivaraj-bh,@srid]
At a glance
- What is it?
- services-flake gives a Nix flake the thing NixOS has and flakes do not: a declarative way to run databases, caches and other daemons natively on macOS and Linux, with per-project data directories and multiple instances of the same service. It is a flake-parts module built on process-compose-flake, and it exists because the alternative was to write the same service definitions twice.
- Who is it for?
- Adopt services-flake if you work in Nix across macOS and Linux and need real services running for development, because the alternative is hand-written process definitions that differ per machine and per project. Do not adopt it if your project already commits to a full devenv configuration, since the comparison table in its own README argues that the two overlap rather than combine.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Nix, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it does: run databases and daemons natively, from a flake, on a laptop
services-flake provides declarative, composable and reproducible services for a Nix development environment, as a process-compose-flake module based on flake-parts. It enables users to have NixOS-like services on macOS and Linux.
That sentence contains the whole thesis. On NixOS, systemd units give you a database running locally with a known version and a known configuration, and on a Mac or a non-NixOS Linux box you normally get nothing. services-flake fills that gap for flakes, which is the increasingly common way to describe a development environment now that devShells and NixOS configurations have converged in practice.
The three problems it names are specific. Run external services like databases and Redis natively across platforms. Enable users to configure multiple instances of these external services. Provide project-specific service configuration and data isolation.
The scenario the README describes makes the isolation point concrete. Consider two projects at ~/code/foo and ~/code/bar. The foo project integrates postgres and nginx, while bar encompasses postgres, pgAdmin and kafka. The postgres data has to remain segregated across these projects, and bar is also designed to run multiple instances of postgres. Both projects are equipped with a flake app, so the result is that anyone on Linux or macOS can clone either project and run nix run .#services to activate the full suite of services with no manual configuration.
That last property is the one that matters in practice. The services become part of the project definition rather than something you set up once and forget, which means a new contributor runs the same stack on their first day.
The comparison with devenv, argued in footnotes
The README includes a comparison table against devenv services, and it is worth reading because the claims come with sources attached rather than assertion.
The rows are macOS support, pure flakes, services as flake apps, multiple instances of a service, share services and no coupling. Both projects get a tick for macOS support. The other four rows are all marked in favour of services-flake, and each has a footnote explaining why.
Pure flakes, because devenv's flakes integration requires you to use the nix shell in impure mode by passing --impure. Services as flake apps, because services-flake produces a flake app you can run with the nix command outside the devShell, whereas with devenv you must use devenv's own CLI, devenv up, inside the devShell. Multiple instances of a service, because services-flake allows configuring multiple instances of the same service and devenv does not, with a link to the upstream issue. Share services, because being built on flake-parts means you can share service and process modules for reuse across flakes and generalise them for customisation through the module system, whereas with devenv you can only share whole devenv configuration as modules. And no coupling, because services-flake exposes process-compose-flake modules for each service that can be reused as long as your project uses flake-parts, while with devenv decoupling is not possible and is not prioritised.
The credits section says the devenv project originally inspired this one, to provide the same thing for Nix flake users. So this is a reimplementation with a different integration philosophy, not a fork.
The README also invites comparison requests through the issue tracker, which is a small sign of confidence in the argument.
Running the examples, and why the override flags are unavoidable
The repository ships an example/ directory with four cases: simple, llm, share-services and without-flake-parts. The justfile has a target for each of the first three, and looking at them tells you more about how the project is meant to be used than the prose does.
The simple example is one line:
cd ./example/simple && nix run . --override-input services-flake ../..The override input is the key part. It points the example flake at the services-flake checkout in the parent directory instead of the published version, which is how you run an example against your local changes. The same pattern appears in the llm example.
The share-services example is more interesting, because it overrides two inputs:
cd ./example/share-services/pgweb && \
nix run . \
--override-input services-flake ../../.. \
--override-input northwind ../northwind \That is the sharing story in practice. A second flake, northwind, is overridden so the example can use a shared service module from it, and the fact that it lives in a sibling directory rather than inside the project is what makes the point about decoupling.
The other example, without-flake-parts, exists to show that the module is usable in a project that does not use flake-parts, which is a compatibility claim rather than a demo.
The justfile also carries the development commands. treefmt formats the tree, cz ch generates a changelog entry from the commits since the last tag, and the doc target runs the documentation server with hot reload from the doc directory, with a separate doc-static target that builds the static site and runs link checking automatically.
Testing: one nix flake check for everything, and a per-service escape hatch
The test setup has a wrinkle that is worth understanding, because it explains a slightly awkward command.
The full test run is a single command:
nix flake check test/ --override-input services-flake . -LThe -L flag is what makes it usable, since it keeps the build log for failures. The override input is the same mechanism as in the examples.
For a specific service, the command is longer:
nix build ./test#checks.$(nix eval --impure --expr "builtins.currentSystem").{{service}} --override-input services-flake . -LThe reason for the complexity is stated in a comment in the justfile: nix flake check does not support individual checks, with a link to the upstream Nix issue. So to run one service's test, the project has to address the check attribute directly, which means building an attribute path with the current system name evaluated inline, and that is why the impure eval flag appears in the middle of the command.
The test directory itself holds a flake and per-service test files named <service>_test.nix, and the run target launches a service whose configuration is defined that way, using cd test && nix run .#{{service}} --override-input services-flake ../.
So a service in this project is tested by actually running it, and the tests live alongside the definitions. That is a heavier test strategy than unit tests of configuration code, and for daemons like postgres or redis it is the only test that means anything anyway.
Data directories, and the isolation guarantee that depends on them
There is a dedicated documentation page for the service data directory, hosted at services.nixos.asia/datadir, and the existence of a whole page on the subject tells you it is the part users get wrong.
The requirement stated in the motivation section is that postgres data remains segregated across projects, and that is a filesystem guarantee rather than a configuration one. Two projects running postgres on the same machine need two different data directories, and if the path is derived from something like the current working directory or a hash of the project, the isolation follows automatically. If it is derived from a fixed path, the two instances collide and you get a corrupt data directory rather than an error.
Multiple instances of the same service in one project have the same requirement, and the README makes it a design goal rather than an accident: enable users to configure multiple instances of these external services.
This is the practical difference between services-flake and the alternatives. A hand-written process-compose file in each project will not give you isolation unless you think about it, and you will think about it once and then forget on the fifth project. A shared module that handles it once handles it everywhere.
The data directory question is also where the operational surprises live. Services that write state, in particular databases, will have their state in a directory that has to survive a rebuild, and getting that wrong means losing your development data every time the flake inputs change.
Maintenance, licensing and the shape of the project
The project is maintained by two named people, shivaraj-bh and srid, and the repository description carries that attribution directly. It is developed by Juspay, and the licence is MIT.
The release history is short and irregular. Version 0.5.0 was published on 2026-10-07, before 0.4.0 from 2024-12-10 and 0.3.0 from 2024-07-29. The last push to the repository was on 2026-10-18, and the repository is not archived, so work continues even though the tagged releases are far apart.
The gap between 0.4.0 and 0.5.0 is nearly two years, and 0.5.0 arriving in October 2026 suggests the project came back to life. If you are evaluating it now, that is good news and it is also a signal to read the CHANGELOG.md before you rely on a behaviour, because a lot may have moved in the gap.
The repository layout is compact. There is a flake.nix, a nix/ directory holding the module code, an example/ directory, a test/ directory, a doc/ directory, a dev/ directory, a justfile for the development commands, a .envrc for direnv, and a .prettierrc.yaml, which tells you the project formats its Nix files with prettier rather than only with nixpkgs-fmt.
The documentation site is services.nixos.asia, with separate pages for getting started, the list of supported services, the data directory, contributing and development. The service list is a page rather than a file in the repository, so it grows as services are added, and there is a demo gif in the doc/ directory showing the thing in motion.
Editorial conclusion
Adopt services-flake if you work in Nix across macOS and Linux and need real services running for development, because the alternative is hand-written process definitions that differ per machine and per project. Do not adopt it if your project already commits to a full devenv configuration, since the comparison table in its own README argues that the two overlap rather than combine. Before you commit a project to it, check the data directory documentation for where your service state lands, and run the example directory first, because the overrides needed to point an example at a local services-flake are the part of the setup that is not obvious from the documentation.
Frequently asked questions
What problem does services-flake solve?
It lets a Nix flake run external services such as databases and Redis natively on macOS and Linux, with multiple instances of the same service supported and per-project data isolation so that two projects can each run their own postgres without sharing state.
How does services-flake differ from devenv services?
The README argues that devenv's flakes integration requires impure mode, that devenv services must be run with devenv up inside the devShell rather than as a flake app, that devenv does not support multiple instances of a service, and that with devenv you can only share whole devenv configuration as modules while services-flake exposes reusable process-compose-flake modules.
How do I run the services-flake examples?
With just, using the ex-simple, ex-llm and ex-share-services targets, or directly with nix run in the example directory. Both forms need --override-input services-flake pointing at the local checkout, and the share-services example also overrides a second flake input named northwind.
How do I run the tests for a single service in services-flake?
nix flake check does not support individual checks, so the project builds the check attribute directly with nix build ./test#checks.<system>.<service>. The justfile provides a test target that evaluates the current system name inline with nix eval --impure.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/juspay-services-flake)Was this useful?