diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## 0.4.0.0 - 2025-05-05
+
+- **REMOVE** `evalArgs`. This removes a dependency on the otherwise unused nix-cmd library. Use `valueFromExpressionString` and a library like `optparse-applicative` instead to create a nicer user experience.
+- Nix 2.28 support
+
 ## 0.3.6.5 - 2024-11-15
 
 - Nix 2.24 support
diff --git a/hercules-ci-cnix-expr.cabal b/hercules-ci-cnix-expr.cabal
--- a/hercules-ci-cnix-expr.cabal
+++ b/hercules-ci-cnix-expr.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.4
 
 name:           hercules-ci-cnix-expr
-version:        0.3.6.5
+version:        0.4.0.0
 synopsis:       Bindings for the Nix evaluator
 category:       Nix, CI, Testing, DevOps
 homepage:       https://docs.hercules-ci.com
@@ -37,6 +37,10 @@
   description: Build for Nix >=2.24
   default: False
 
+flag nix-2_25
+  description: Build for Nix >=2.25
+  default: False
+
 flag ide
   description: Whether to enable IDE workarounds. You shouldn't need this.
   default: False
@@ -125,10 +129,6 @@
       nix-store >= 2.4
     , nix-expr >= 2.4
     , nix-main >= 2.4
-  if flag(nix-2_8)
-    pkgconfig-depends:
-      -- MixEvalArgs has moved here
-      nix-cmd >= 2.8
   if flag(nix-2_24)
     pkgconfig-depends:
       nix-flake
@@ -169,3 +169,7 @@
   build-tool-depends:
       hspec-discover:hspec-discover == 2.*
   default-language: Haskell2010
+
+  -- Missing nix-fetchers.pc upstream in Nix 2.24
+  if flag(nix-2_24) && ! flag(nix-2_25)
+    extra-libraries: nixfetchers
diff --git a/include/hercules-ci-cnix/expr.hxx b/include/hercules-ci-cnix/expr.hxx
--- a/include/hercules-ci-cnix/expr.hxx
+++ b/include/hercules-ci-cnix/expr.hxx
@@ -1,6 +1,11 @@
 #pragma once
 
+#if NIX_IS_AT_LEAST(2,28,0)
+#include <nix/store/derivations.hh>
+#else
 #include "derivations.hh"
+#endif
+
 #include <hercules-ci-cnix/store.hxx>
 
 typedef nix::Strings::iterator StringsIterator;
diff --git a/src/Hercules/CNix/Expr.hs b/src/Hercules/CNix/Expr.hs
--- a/src/Hercules/CNix/Expr.hs
+++ b/src/Hercules/CNix/Expr.hs
@@ -34,7 +34,6 @@
     evalFile,
     newStrings,
     appendString,
-    evalArgs,
     autoCallFunction,
     isDerivation,
     isFunctor,
@@ -105,36 +104,41 @@
 
 C.include "<math.h>"
 
-C.include "<nix/config.h>"
+#if NIX_IS_AT_LEAST(2, 28, 0)
 
-C.include "<nix/shared.hh>"
+C.include "<nix/util/config-global.hh>"
+C.include "<nix/store/store-api.hh>"
+C.include "<nix/store/globals.hh>"
+C.include "<nix/expr/eval.hh>"
+C.include "<nix/expr/eval-inline.hh>"
+C.include "<nix/expr/get-drvs.hh>"
+C.include "<nix/flake/flake.hh>"
+C.include "<nix/flake/flakeref.hh>"
+C.include "<nix/flake/settings.hh>"
+C.include "<nix/fetchers/fetch-settings.hh>"
+C.include "<nix/main/shared.hh>"
 
+#else
+C.include "<nix/config.h>"
+C.include "<nix/shared.hh>"
 C.include "<nix/eval.hh>"
-
 C.include "<nix/eval-inline.hh>"
-
 C.include "<nix/store-api.hh>"
-
-C.include "<nix/common-eval-args.hh>"
-
 C.include "<nix/get-drvs.hh>"
-
 C.include "<nix/derivations.hh>"
-
 C.include "<nix/globals.hh>"
-
 C.include "<nix/flake/flake.hh>"
-
 C.include "<nix/flake/flakeref.hh>"
-
-#if NIX_IS_AT_LEAST(2,19,0)
+#  if NIX_IS_AT_LEAST(2,19,0)
 C.include "<nix/args/root.hh>"
-#endif
-
-#if NIX_IS_AT_LEAST(2,24,0)
+#  endif
+#  if NIX_IS_AT_LEAST(2,24,0)
 C.include "<nix/config-global.hh>"
 C.include "<nix/eval-gc.hh>"
-C.include "<nix/common-eval-args.hh>"
+C.include "<nix/flake/settings.hh>"
+C.include "<nix/fetch-settings.hh>"
+C.include "<nix/eval-settings.hh>"
+#  endif
 #endif
 
 C.include "hercules-ci-cnix/expr.hxx"
@@ -153,10 +157,18 @@
 
 C.verbatim "\nGC_API void GC_CALL GC_throw_bad_alloc() { throw std::bad_alloc(); }\n"
 
+C.verbatim "nix::flake::Settings flakeSettings;"
+C.verbatim "nix::fetchers::Settings fetchSettings;"
+C.verbatim "static bool readOnlyMode = false;"
+C.verbatim "nix::EvalSettings evalSettings(readOnlyMode);"
+
 init :: IO ()
 init =
   void
     [C.throwBlock| void {
+      { auto _ = GlobalConfig::Register(&flakeSettings); }
+      { auto _ = GlobalConfig::Register(&fetchSettings); }
+      { auto _ = GlobalConfig::Register(&evalSettings); }
       nix::initNix();
       nix::initGC();
 #if NIX_IS_AT_LEAST(2,15,0)
@@ -171,7 +183,9 @@
 #endif
       nix::settings.experimentalFeatures.assign(features);
 #endif
-#if NIX_IS_AT_LEAST(2,24,0)
+#if NIX_IS_AT_LEAST(2,28,0)
+      flakeSettings.configureEvalSettings(evalSettings);
+#elif NIX_IS_AT_LEAST(2,24,0)
       nix::flake::initLib(flakeSettings);
 #endif
     } |]
@@ -370,33 +384,6 @@
   [C.block| void {
     $(Strings *ss)->push_back(std::string($bs-ptr:s, $bs-len:s));
   }|]
-
-#if NIX_IS_AT_LEAST(2,19,0)
-C.verbatim "struct EvalArgs : nix::RootArgs, nix::MixEvalArgs { };"
-#else
-C.verbatim "struct EvalArgs : nix::MixEvalArgs { };"
-#endif
-
-evalArgs :: Ptr EvalState -> [ByteString] -> IO (Value NixAttrs)
-evalArgs evalState args = do
-  argsStrings <- newStrings
-  forM_ args $ appendString argsStrings
-  fmap unsafeAssertType . mkRawValue
-    =<< [C.throwBlock| Value * {
-      Strings *args = $(Strings *argsStrings);
-      struct EvalArgs evalArgs;
-      Bindings *autoArgs;
-      EvalState &state = *$(EvalState *evalState);
-
-      evalArgs.parseCmdline(*args);
-      autoArgs = evalArgs.getAutoArgs(state);
-      if (!autoArgs) {
-        throw nix::Error("Could not evaluate automatic arguments");
-      }
-      Value *r = new (NoGC) Value ();
-      r->mkAttrs(autoArgs);
-      return r;
-    }|]
 
 autoCallFunction :: Ptr EvalState -> RawValue -> Value NixAttrs -> IO RawValue
 autoCallFunction evalState (RawValue fun) (Value (RawValue autoArgs)) =
diff --git a/src/Hercules/CNix/Expr/Raw.hs b/src/Hercules/CNix/Expr/Raw.hs
--- a/src/Hercules/CNix/Expr/Raw.hs
+++ b/src/Hercules/CNix/Expr/Raw.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TemplateHaskell #-}
 
@@ -19,18 +20,20 @@
 
 C.context context
 
-C.include "<nix/config.h>"
+#if NIX_IS_AT_LEAST(2, 28, 0)
 
-C.include "<nix/eval.hh>"
+C.include "<nix/expr/eval.hh>"
+C.include "<nix/expr/eval-inline.hh>"
 
+#else
+C.include "<nix/config.h>"
+C.include "<nix/eval.hh>"
 C.include "<nix/eval-inline.hh>"
+#endif
 
 C.include "<hercules-ci-cnix/expr.hxx>"
-
 C.include "<gc/gc.h>"
-
 C.include "<gc/gc_cpp.h>"
-
 C.include "<gc/gc_allocator.h>"
 
 C.using "namespace nix"
diff --git a/src/Hercules/CNix/Expr/Typed.hs b/src/Hercules/CNix/Expr/Typed.hs
--- a/src/Hercules/CNix/Expr/Typed.hs
+++ b/src/Hercules/CNix/Expr/Typed.hs
@@ -48,23 +48,22 @@
 
 C.include "<math.h>"
 
-C.include "<nix/config.h>"
+#if NIX_IS_AT_LEAST(2, 28, 0)
 
-C.include "<nix/shared.hh>"
+C.include "<nix/expr/eval.hh>"
+C.include "<nix/expr/eval-inline.hh>"
 
+#else
+C.include "<nix/config.h>"
+C.include "<nix/shared.hh>"
 C.include "<nix/eval.hh>"
-
 C.include "<nix/eval-inline.hh>"
-
 C.include "<nix/store-api.hh>"
-
-C.include "<nix/common-eval-args.hh>"
-
+-- C.include "<nix/common-eval-args.hh>"
 C.include "<nix/get-drvs.hh>"
-
 C.include "<nix/derivations.hh>"
-
 C.include "<nix/globals.hh>"
+#endif
 
 C.include "hercules-ci-cnix/expr.hxx"
 
@@ -161,7 +160,9 @@
 
 getInt :: Value NixInt -> IO Int64
 getInt (Value (RawValue v)) =
-#if NIX_IS_AT_LEAST(2,24,0)
+#if NIX_IS_AT_LEAST(2,27,0)
+  [C.exp| int64_t { $(Value *v)->integer().value }|]
+#elif NIX_IS_AT_LEAST(2,24,0)
   [C.exp| int64_t { $(Value *v)->integer() }|]
 #else
   [C.exp| int64_t { $(Value *v)->integer }|]
