diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,11 @@
-## [_Unreleased_](https://github.com/freckle/stackctl/compare/v1.1.1.1...main)
+## [_Unreleased_](https://github.com/freckle/stackctl/compare/v1.1.2.0...main)
+
+## [v1.1.2.0](https://github.com/freckle/stackctl/compare/v1.1.1.1...v1.1.2.0)
+
+- Fix incorrect ordering of log-messages by setting `LOG_CONCURRENCY=1`
+- Fix potential coloring of changes being redirected to a file
+- Make `PATH` optional (again) in `stackctl changes`
+- Add `--no-flip` to `stackctl capture`
 
 ## [v1.1.1.1](https://github.com/freckle/stackctl/compare/v1.1.1.0...v1.1.1.1)
 
diff --git a/src/Stackctl/CLI.hs b/src/Stackctl/CLI.hs
--- a/src/Stackctl/CLI.hs
+++ b/src/Stackctl/CLI.hs
@@ -75,7 +75,11 @@
   -> AppT (App options) m a
   -> m a
 runAppT options f = do
-  envLogSettings <- liftIO LoggingEnv.parse
+  envLogSettings <-
+    liftIO
+    . LoggingEnv.parseWith
+    . setLogSettingsConcurrency (Just 1)
+    $ defaultLogSettings
 
   logger <- newLogger $ adjustLogSettings
     (options ^. colorOptionL)
diff --git a/src/Stackctl/Colors.hs b/src/Stackctl/Colors.hs
--- a/src/Stackctl/Colors.hs
+++ b/src/Stackctl/Colors.hs
@@ -3,12 +3,14 @@
   ( Colors(..)
   , HasColorOption
   , getColorsStdout
+  , getColorsLogger
   , noColors
   ) where
 
 import Stackctl.Prelude
 
 import Blammo.Logging.Colors
+import Blammo.Logging.Logger
 import Stackctl.ColorOption (HasColorOption(..), colorHandle)
 
 -- | Return 'Colors' based on options and 'stdout'
@@ -23,6 +25,10 @@
   colorOption <- view colorOptionL
   c <- colorHandle h colorOption
   pure $ getColors c
+
+-- | Return 'Colors' consistent with the ambient 'Logger'
+getColorsLogger :: (MonadReader env m, HasLogger env) => m Colors
+getColorsLogger = view $ loggerL . to (getColors . getLoggerShouldColor)
 
 noColors :: Colors
 noColors = getColors False
diff --git a/src/Stackctl/Commands.hs b/src/Stackctl/Commands.hs
--- a/src/Stackctl/Commands.hs
+++ b/src/Stackctl/Commands.hs
@@ -10,7 +10,7 @@
 
 import Stackctl.AWS
 import Stackctl.AWS.Scope
-import Stackctl.ColorOption
+import Stackctl.Colors
 import Stackctl.DirectoryOption
 import Stackctl.FilterOption
 import Stackctl.Spec.Capture
@@ -46,11 +46,11 @@
   }
 
 changes
-  :: ( HasAwsScope env
+  :: ( HasLogger env
+     , HasAwsScope env
      , HasAwsEnv env
      , HasDirectoryOption env
      , HasFilterOption env
-     , HasColorOption env
      )
   => Subcommand ChangesOptions env
 changes = Subcommand
@@ -66,7 +66,6 @@
      , HasAwsEnv env
      , HasDirectoryOption env
      , HasFilterOption env
-     , HasColorOption env
      )
   => Subcommand DeployOptions env
 deploy = Subcommand
diff --git a/src/Stackctl/Spec/Capture.hs b/src/Stackctl/Spec/Capture.hs
--- a/src/Stackctl/Spec/Capture.hs
+++ b/src/Stackctl/Spec/Capture.hs
@@ -11,12 +11,14 @@
 import Stackctl.AWS.Scope
 import Stackctl.DirectoryOption (HasDirectoryOption(..))
 import Stackctl.Spec.Generate
+import Stackctl.StackSpec
 
 data CaptureOptions = CaptureOptions
   { scoAccountName :: Maybe Text
   , scoTemplatePath :: Maybe FilePath
   , scoStackPath :: Maybe FilePath
   , scoDepends :: Maybe [StackName]
+  , scoTemplateFormat :: TemplateFormat
   , scoStackName :: StackName
   }
 
@@ -47,6 +49,10 @@
       <> metavar "STACK"
       <> help "Add a dependency on STACK"
       )))
+    <*> flag TemplateFormatYaml TemplateFormatJson
+      (  long "no-flip"
+      <> help "Don't flip JSON templates to Yaml"
+      )
     <*> (StackName <$> argument str
       (  metavar "STACK"
       <> help "Name of deployed Stack to capture"
@@ -76,6 +82,7 @@
   void $ local (awsScopeL %~ setScopeName) $ generate Generate
     { gOutputDirectory = dir
     , gTemplatePath = scoTemplatePath
+    , gTemplateFormat = scoTemplateFormat
     , gStackPath = scoStackPath
     , gStackName = scoStackName
     , gDepends = scoDepends
@@ -83,5 +90,5 @@
     , gParameters = parameters stack
     , gCapabilities = capabilities stack
     , gTags = tags stack
-    , gTemplate = template
+    , gTemplateBody = templateBodyFromValue template
     }
diff --git a/src/Stackctl/Spec/Changes.hs b/src/Stackctl/Spec/Changes.hs
--- a/src/Stackctl/Spec/Changes.hs
+++ b/src/Stackctl/Spec/Changes.hs
@@ -6,6 +6,7 @@
 
 import Stackctl.Prelude
 
+import Blammo.Logging.Logger (pushLoggerLn)
 import qualified Data.Text.IO as T
 import Options.Applicative
 import Stackctl.AWS hiding (action)
@@ -22,7 +23,7 @@
 data ChangesOptions = ChangesOptions
   { scoFormat :: Format
   , scoParameters :: [Parameter]
-  , scoOutput :: FilePath
+  , scoOutput :: Maybe FilePath
   }
 
 -- brittany-disable-next-binding
@@ -31,11 +32,11 @@
 runChangesOptions = ChangesOptions
   <$> formatOption
   <*> many parameterOption
-  <*> argument str
+  <*> optional (argument str
     (  metavar "PATH"
-    <> help "Where to write the changes summary"
+    <> help "Write changes summary to PATH"
     <> action "file"
-    )
+    ))
 
 runChanges
   :: ( MonadMask m
@@ -43,17 +44,17 @@
      , MonadResource m
      , MonadLogger m
      , MonadReader env m
+     , HasLogger env
      , HasAwsScope env
      , HasAwsEnv env
      , HasDirectoryOption env
      , HasFilterOption env
-     , HasColorOption env
      )
   => ChangesOptions
   -> m ()
 runChanges ChangesOptions {..} = do
   -- Clear file before starting, as we have to use append for each spec
-  liftIO $ T.writeFile scoOutput ""
+  liftIO $ traverse_ (`T.writeFile` "") scoOutput
 
   specs <- discoverSpecs
 
@@ -66,8 +67,14 @@
           logError $ "Error creating ChangeSet" :# ["error" .= err]
           exitFailure
         Right mChangeSet -> do
-          colors <- getColorsStdout
+          colors <- case scoOutput of
+            Nothing -> getColorsLogger
+            Just{} -> pure noColors
+
           let
             name = pack $ stackSpecPathFilePath $ stackSpecSpecPath spec
             formatted = formatChangeSet colors name scoFormat mChangeSet
-          liftIO $ T.appendFile scoOutput $ formatted <> "\n"
+
+          case scoOutput of
+            Nothing -> pushLoggerLn formatted
+            Just p -> liftIO $ T.appendFile p $ formatted <> "\n"
diff --git a/src/Stackctl/Spec/Deploy.hs b/src/Stackctl/Spec/Deploy.hs
--- a/src/Stackctl/Spec/Deploy.hs
+++ b/src/Stackctl/Spec/Deploy.hs
@@ -7,7 +7,7 @@
 
 import Stackctl.Prelude
 
-import Blammo.Logging.Logger (pushLogStrLn)
+import Blammo.Logging.Logger (pushLoggerLn)
 import qualified Data.Text as T
 import Data.Time (defaultTimeLocale, formatTime, utcToLocalZonedTime)
 import Options.Applicative
@@ -22,7 +22,6 @@
 import Stackctl.Spec.Changes.Format
 import Stackctl.Spec.Discover
 import Stackctl.StackSpec
-import System.Log.FastLogger (toLogStr)
 import UnliftIO.Directory (createDirectoryIfMissing)
 
 data DeployOptions = DeployOptions
@@ -63,7 +62,6 @@
      , HasAwsEnv env
      , HasDirectoryOption env
      , HasFilterOption env
-     , HasColorOption env
      )
   => DeployOptions
   -> m ()
@@ -137,15 +135,14 @@
      , MonadReader env m
      , HasLogger env
      , HasAwsEnv env
-     , HasColorOption env
      )
   => DeployConfirmation
   -> ChangeSet
   -> m ()
 deployChangeSet confirmation changeSet = do
-  colors <- getColorsStdout
+  colors <- getColorsLogger
 
-  pushLogger $ formatTTY colors (unStackName stackName) $ Just changeSet
+  pushLoggerLn $ formatTTY colors (unStackName stackName) $ Just changeSet
 
   case confirmation of
     DeployWithConfirmation -> promptContinue
@@ -184,15 +181,14 @@
      , MonadReader env m
      , HasLogger env
      , HasAwsEnv env
-     , HasColorOption env
      )
   => StackName
   -> Maybe Text -- ^ StackEventId
   -> m a
 tailStackEventsSince stackName mLastId = do
-  colors <- getColorsStdout
+  colors <- getColorsLogger
   events <- awsCloudFormationDescribeStackEvents stackName mLastId
-  traverse_ (pushLogger <=< formatStackEvent colors) $ reverse events
+  traverse_ (pushLoggerLn <=< formatStackEvent colors) $ reverse events
 
   -- Without this small delay before looping, our requests seem to hang
   -- intermittently (without errors) and often we miss events.
@@ -229,8 +225,3 @@
 
 getLastEventId :: [StackEvent] -> Maybe Text
 getLastEventId = fmap (^. stackEvent_eventId) . listToMaybe
-
-pushLogger :: (MonadIO m, MonadReader env m, HasLogger env) => Text -> m ()
-pushLogger msg = do
-  logger <- view loggerL
-  pushLogStrLn logger $ toLogStr msg
diff --git a/src/Stackctl/Spec/Generate.hs b/src/Stackctl/Spec/Generate.hs
--- a/src/Stackctl/Spec/Generate.hs
+++ b/src/Stackctl/Spec/Generate.hs
@@ -1,11 +1,11 @@
 module Stackctl.Spec.Generate
   ( Generate(..)
   , generate
+  , TemplateFormat(..)
   ) where
 
 import Stackctl.Prelude
 
-import Data.Aeson
 import Stackctl.AWS
 import Stackctl.AWS.Scope
 import Stackctl.Action
@@ -17,18 +17,24 @@
 data Generate = Generate
   { gOutputDirectory :: FilePath
   , gTemplatePath :: Maybe FilePath
-  -- ^ If not given will use @{stack-name}.yaml@
+  -- ^ If not given, will use @{stack-name}.(yaml|json)@
+  , gTemplateFormat :: TemplateFormat
+  -- ^ Ignored if 'gTemplatePath' is given
   , gStackPath :: Maybe FilePath
-  -- ^ If not given will use @{stack-name}.yaml@
+  -- ^ If not given, will use @{stack-name}.yaml@
   , gStackName :: StackName
   , gDepends :: Maybe [StackName]
   , gActions :: Maybe [Action]
   , gParameters :: Maybe [Parameter]
   , gCapabilities :: Maybe [Capability]
   , gTags :: Maybe [Tag]
-  , gTemplate :: Value
+  , gTemplateBody :: TemplateBody
   }
 
+data TemplateFormat
+  = TemplateFormatYaml
+  | TemplateFormatJson
+
 generate
   :: ( MonadMask m
      , MonadUnliftIO m
@@ -40,13 +46,18 @@
   -> m FilePath
 generate Generate {..} = do
   let
-    path = unpack (unStackName gStackName) <.> "yaml"
-    stackPath = fromMaybe path gStackPath
+    defaultStackPath = unpack (unStackName gStackName) <.> "yaml"
+    defaultTemplatePath =
+      unpack (unStackName gStackName) <.> case gTemplateFormat of
+        TemplateFormatYaml -> "yaml"
+        TemplateFormatJson -> "json"
 
+    stackPath = fromMaybe defaultStackPath gStackPath
+
   specPath <- buildSpecPath gStackName stackPath
 
   let
-    templatePath = fromMaybe path gTemplatePath
+    templatePath = fromMaybe defaultTemplatePath gTemplatePath
     specYaml = StackSpecYaml
       { ssyTemplate = templatePath
       , ssyDepends = gDepends
@@ -60,5 +71,5 @@
 
   withThreadContext ["stackName" .= stackSpecStackName stackSpec] $ do
     logInfo "Generating specification"
-    writeStackSpec gOutputDirectory stackSpec gTemplate
+    writeStackSpec gOutputDirectory stackSpec gTemplateBody
     pure $ stackSpecPathFilePath specPath
diff --git a/src/Stackctl/StackSpec.hs b/src/Stackctl/StackSpec.hs
--- a/src/Stackctl/StackSpec.hs
+++ b/src/Stackctl/StackSpec.hs
@@ -8,6 +8,8 @@
   , stackSpecCapabilities
   , stackSpecTags
   , buildStackSpec
+  , TemplateBody
+  , templateBodyFromValue
   , writeStackSpec
   , readStackSpec
   , createChangeSet
@@ -18,6 +20,7 @@
 
 import qualified CfnFlip
 import Data.Aeson
+import qualified Data.ByteString.Lazy as BSL
 import Data.List.Extra (nubOrdOn)
 import qualified Data.Yaml as Yaml
 import Stackctl.AWS
@@ -25,6 +28,7 @@
 import Stackctl.Sort
 import Stackctl.StackSpecPath
 import Stackctl.StackSpecYaml
+import System.FilePath (takeExtension)
 import UnliftIO.Directory (createDirectoryIfMissing)
 
 data StackSpec = StackSpec
@@ -65,20 +69,47 @@
 buildStackSpec :: FilePath -> StackSpecPath -> StackSpecYaml -> StackSpec
 buildStackSpec = StackSpec
 
+data TemplateBody
+  = TemplateText Text
+  | TemplateJson Value
+
+newtype UnexpectedTemplateJson = UnexpectedTemplateJson
+  { _unexpectedTemplateJsonExtension :: String
+  }
+  deriving stock Show
+
+instance Exception UnexpectedTemplateJson where
+  displayException (UnexpectedTemplateJson ext) =
+    "TemplateJson must be written to .yaml or .json, encountered "
+      <> ext
+      <> ". To write to an arbitrary path, use TemplateText."
+
+templateBodyFromValue :: Value -> TemplateBody
+templateBodyFromValue = \case
+  String x -> TemplateText x
+  v -> TemplateJson v
+
+writeTemplateBody :: MonadUnliftIO m => FilePath -> TemplateBody -> m ()
+writeTemplateBody path body = do
+  createDirectoryIfMissing True dir
+
+  case (body, ext) of
+    (TemplateText t, _) -> writeFileUtf8 path t
+    (TemplateJson v, ".yaml") -> CfnFlip.jsonToYamlFile path v
+    (TemplateJson v, ".json") -> writeFileBinary path $ BSL.toStrict $ encode v
+    (TemplateJson _, _) -> throwIO $ UnexpectedTemplateJson ext
+ where
+  dir = takeDirectory path
+  ext = takeExtension path
+
 writeStackSpec
   :: MonadUnliftIO m
   => FilePath -- ^ Parent directory
   -> StackSpec
-  -> Value -- ^ Template body
+  -> TemplateBody
   -> m ()
 writeStackSpec parent stackSpec@StackSpec {..} templateBody = do
-  createDirectoryIfMissing True $ takeDirectory templatePath
-
-  case templateBody of
-    -- Already Yaml
-    String x -> writeFileUtf8 templatePath x
-    _ -> CfnFlip.jsonToYamlFile templatePath templateBody
-
+  writeTemplateBody templatePath templateBody
   createDirectoryIfMissing True $ takeDirectory specPath
   liftIO $ Yaml.encodeFile specPath ssSpecBody
  where
diff --git a/stackctl.cabal b/stackctl.cabal
--- a/stackctl.cabal
+++ b/stackctl.cabal
@@ -1,6 +1,6 @@
 cabal-version:   1.18
 name:            stackctl
-version:         1.1.1.1
+version:         1.1.2.0
 license:         MIT
 license-file:    LICENSE
 copyright:       2022 Renaissance Learning Inc
@@ -74,7 +74,7 @@
         -Wno-unsafe -optP-Wno-nonportable-include-path
 
     build-depends:
-        Blammo >=1.1.1.0,
+        Blammo >=1.1.1.1,
         Glob,
         aeson,
         aeson-casing,
@@ -93,7 +93,6 @@
         errors,
         exceptions,
         extra,
-        fast-logger,
         filepath,
         lens,
         lens-aeson,
