diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).
 
+## [1.1.1] - 2026-10-01
+
+### Changed
+
+- `haxl`, `haxlWithWrites`, `haxlWithStats` no longer clone the environment.
+
 ## [1.1.0] - 2026-08-04
 
 ### Added
diff --git a/haxl-effectful.cabal b/haxl-effectful.cabal
--- a/haxl-effectful.cabal
+++ b/haxl-effectful.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: haxl-effectful
-version: 1.1.0
+version: 1.1.1
 category: Concurrency
 synopsis: Effectful bindings for Haxl
 description:
@@ -67,7 +67,7 @@
 
   build-depends:
     base >=4.10 && <5,
-    effectful >=2.6 && <2.7,
+    effectful >=2.6 && <2.8,
     hashable >=1.5 && <1.6,
 
 library
diff --git a/src/Effectful/Haxl.hs b/src/Effectful/Haxl.hs
--- a/src/Effectful/Haxl.hs
+++ b/src/Effectful/Haxl.hs
@@ -256,13 +256,13 @@
 haxl :: forall u w es a. (Monoid w) => GenHaxl u w es a -> Eff (Haxl u w ': es) a
 haxl g = do
     env <- initEnv
-    inject $ unsafeConcUnliftIO Persistent Unlimited $ Haxl.runHaxl env . unHaxl g
+    inject $ unsafeSeqUnliftIO $ Haxl.runHaxl env . unHaxl g
 
 -- | Like 'haxl', but also return everything written via the 'w' monoid during the run.
 haxlWithWrites :: forall u w es a. (Monoid w) => GenHaxl u w es a -> Eff (Haxl u w ': es) (a, w)
 haxlWithWrites g = do
     env <- initEnv
-    inject $ unsafeConcUnliftIO Persistent Unlimited $ Haxl.runHaxlWithWrites env . unHaxl g
+    inject $ unsafeSeqUnliftIO $ Haxl.runHaxlWithWrites env . unHaxl g
 
 -- | Like 'haxl', but also return the 'Stats' collected during the run.
 --
@@ -271,7 +271,7 @@
 haxlWithStats :: forall u w es a. (Monoid w) => GenHaxl u w es a -> Eff (Haxl u w ': es) (a, Stats)
 haxlWithStats g = do
     env <- initEnv
-    a <- inject $ unsafeConcUnliftIO Persistent Unlimited $ Haxl.runHaxl env . unHaxl g
+    a <- inject $ unsafeSeqUnliftIO $ Haxl.runHaxl env . unHaxl g
     stats <- unsafeEff_ . readIORef $ statsRef env
     pure (a, stats)
 
diff --git a/test/ExampleDataSource.hs b/test/ExampleDataSource.hs
--- a/test/ExampleDataSource.hs
+++ b/test/ExampleDataSource.hs
@@ -28,7 +28,7 @@
 import System.IO (hPutStr, stderr)
 import Prelude
 
--- Here is an example minimal data source.  Our data source will have
+-- Here is an example minimal data source. Our data source will have
 -- two requests:
 --
 --   countAardvarks :: String -> Haxl Int
@@ -48,13 +48,13 @@
     ListWombats :: Id -> ExampleReq [Id]
 
 -- The request type (ExampleReq) is parameterized by the result type of
--- each request.  Each request might have a different result, so we use a
+-- each request. Each request might have a different result, so we use a
 -- GADT - a data type in which each constructor may have different type
 -- parameters. Here CountAardvarks is a request that takes a String
 -- argument and its result is Int, whereas ListWombats takes an Id
 -- argument and returns a [Id].
 
--- The request type needs instances for 'Eq1' and 'Hashable1'.  These
+-- The request type needs instances for 'Eq1' and 'Hashable1'. These
 -- are like 'Eq' and 'Hashable', but for types with one parameter
 -- where the parameter is irrelevant for hashing and equality.
 -- These two instances are used to support caching of requests.
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -5,6 +5,8 @@
 
 module Main where
 
+import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar)
+import Control.Monad (replicateM)
 import Data.Functor ((<&>))
 import Data.List qualified as List
 import Data.Maybe (mapMaybe)
@@ -18,7 +20,7 @@
 import Effectful.Haxl as Haxl
 import Effectful.Hspec
 import Effectful.Prim (Prim, runPrim)
-import Effectful.Prim.IORef (modifyIORef', newIORef, readIORef)
+import Effectful.Prim.IORef (atomicModifyIORef', modifyIORef', newIORef, readIORef)
 import ExampleDataSource (Id (..))
 import ExampleDataSource qualified
 import GHC.Stack (HasCallStack)
@@ -66,6 +68,9 @@
                 asyncExceptionTest
             describe "cache dump" do
                 dumpCacheTest
+            describe "liftEff" do
+                liftEffTest
+                concurrentLiftEffTest
 
 -- * Helpers
 
@@ -368,6 +373,38 @@
     r `shouldSatisfy` \case
         Left ThreadKilled -> True
         _ -> False
+
+-- * liftEff
+
+liftEffTest :: forall es. (Haxl () () :> es, Hspec :> es, Prim :> es) => Expectation es
+liftEffTest = it "runs an Eff action and sees its effect" do
+    ref <- newIORef (0 :: Int)
+    r <- inject . haxl @() @() $ do
+        liftEff $ modifyIORef' ref (+ 1)
+        liftEff $ readIORef ref
+    r `shouldBe` 1
+    final <- readIORef ref
+    final `shouldBe` 1
+
+concurrentLiftEffTest
+    :: forall es
+     . (Haxl () () :> es, Hspec :> es, Prim :> es, IOE :> es)
+    => Expectation es
+concurrentLiftEffTest = it "runs liftEff correctly across many concurrent haxl calls" do
+    ref <- newIORef (0 :: Int)
+    let go :: GenHaxl () () es Int
+        go = do
+            n <- liftEff $ atomicModifyIORef' ref (\n -> (n + 1, n + 1))
+            _ <- ExampleDataSource.countAardvarks "a" -- also exercise a real fetch alongside liftEff
+            pure n
+    results <- concurrently 64 . inject $ haxl @() @() go
+    List.sort results `shouldBe` [1 .. 64]
+
+concurrently :: (IOE :> es) => Int -> Eff es a -> Eff es [a]
+concurrently n act = withEffToIO (ConcUnlift Persistent Unlimited) \unlift -> do
+    mvs <- replicateM n newEmptyMVar
+    mapM_ (\mv -> forkIO (unlift act >>= putMVar mv)) mvs
+    mapM takeMVar mvs
 
 -- * Cache dump
 
