diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
-## [_Unreleased_](https://github.com/freckle/stackctl/compare/v1.4.0.0...main)
+## [_Unreleased_](https://github.com/freckle/stackctl/compare/v1.4.0.1...main)
+
+## [v1.4.0.1](https://github.com/freckle/stackctl/compare/v1.4.0.0...v1.4.0.1)
+
+- Document and read a consistently-named `STACKCTL_FILTER` for `--filter`. For
+  now, the old and incorrect `STACKCTL_FILTERS` will still work.
 
 ## [v1.4.0.0](https://github.com/freckle/stackctl/compare/v1.3.0.2...v1.4.0.0)
 
diff --git a/src/Stackctl/AWS/Scope.hs b/src/Stackctl/AWS/Scope.hs
--- a/src/Stackctl/AWS/Scope.hs
+++ b/src/Stackctl/AWS/Scope.hs
@@ -1,13 +1,18 @@
 module Stackctl.AWS.Scope
   ( AwsScope(..)
+  , awsScopeSpecPatterns
+  , awsScopeSpecStackName
   , HasAwsScope(..)
   , fetchAwsScope
   ) where
 
 import Stackctl.Prelude
 
+import qualified Data.Text as T
 import Stackctl.AWS
 import System.Environment (lookupEnv)
+import System.FilePath (joinPath, splitPath)
+import System.FilePath.Glob (Pattern, compile, match)
 
 data AwsScope = AwsScope
   { awsAccountId :: AccountId
@@ -16,6 +21,42 @@
   }
   deriving stock (Eq, Show, Generic)
   deriving anyclass ToJSON
+
+awsScopeSpecPatterns :: AwsScope -> [Pattern]
+awsScopeSpecPatterns AwsScope {..} =
+  [ compile
+    $ "stacks"
+    </> unpack (unAccountId awsAccountId)
+    <> ".*"
+    </> unpack (fromRegion awsRegion)
+    <> "**"
+    </> "*"
+    <.> "yaml"
+  , compile
+    $ "stacks"
+    </> "*."
+    <> unpack (unAccountId awsAccountId)
+    </> unpack (fromRegion awsRegion)
+    <> "**"
+    </> "*"
+    <.> "yaml"
+  ]
+
+awsScopeSpecStackName :: AwsScope -> FilePath -> Maybe StackName
+awsScopeSpecStackName scope path = do
+  guard $ any (`match` path) $ awsScopeSpecPatterns scope
+
+  -- once we've guarded that the path matches our scope patterns, we can play it
+  -- pretty fast and loose with the "parsing" step
+  pure
+    $ path                -- stacks/account/region/x/y.yaml
+    & splitPath           -- [stacks/, account/, region/, x/, y.yaml]
+    & drop 3              -- [x, y.yaml]
+    & joinPath            -- x/y.yaml
+    & dropExtension       -- x/y
+    & pack
+    & T.replace "/" "-"   -- x-y
+    & StackName
 
 class HasAwsScope env where
   awsScopeL :: Lens' env AwsScope
diff --git a/src/Stackctl/FilterOption.hs b/src/Stackctl/FilterOption.hs
--- a/src/Stackctl/FilterOption.hs
+++ b/src/Stackctl/FilterOption.hs
@@ -6,6 +6,7 @@
   , filterOption
   , filterOptionFromPaths
   , filterOptionFromText
+  , filterOptionToPaths
   , filterStackSpecs
   ) where
 
@@ -37,12 +38,14 @@
   filterOptionL = id
 
 envFilterOption :: String -> Env.Parser Env.Error FilterOption
-envFilterOption items =
-  Env.var (first Env.UnreadError . readFilterOption) "FILTERS"
-    $ Env.help
-    $ "Filter "
-    <> items
-    <> " by patterns"
+envFilterOption items = var "FILTERS" <|> var "FILTER"
+ where
+  var name =
+    Env.var (first Env.UnreadError . readFilterOption) name
+      $ Env.help
+      $ "Filter "
+      <> items
+      <> " by patterns"
 
 filterOption :: String -> Parser FilterOption
 filterOption items = option (eitherReader readFilterOption) $ mconcat
@@ -92,6 +95,9 @@
 
 defaultFilterOption :: FilterOption
 defaultFilterOption = filterOptionFromPaths $ pure "**/*"
+
+filterOptionToPaths :: FilterOption -> [FilePath]
+filterOptionToPaths = map decompile . NE.toList . unFilterOption
 
 filterStackSpecs :: FilterOption -> [StackSpec] -> [StackSpec]
 filterStackSpecs fo =
diff --git a/src/Stackctl/RemovedStack.hs b/src/Stackctl/RemovedStack.hs
new file mode 100644
--- /dev/null
+++ b/src/Stackctl/RemovedStack.hs
@@ -0,0 +1,43 @@
+module Stackctl.RemovedStack
+  ( inferRemovedStacks
+  ) where
+
+import Stackctl.Prelude
+
+import Control.Error.Util (hoistMaybe)
+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
+import Stackctl.AWS.CloudFormation
+import Stackctl.AWS.Core
+import Stackctl.AWS.Scope
+import Stackctl.FilterOption
+import UnliftIO.Directory (doesFileExist)
+
+inferRemovedStacks
+  :: ( MonadUnliftIO m
+     , MonadResource m
+     , MonadReader env m
+     , HasAwsEnv env
+     , HasAwsScope env
+     , HasFilterOption env
+     )
+  => m [Stack]
+inferRemovedStacks = do
+  scope <- view awsScopeL
+  paths <- view $ filterOptionL . to filterOptionToPaths
+  catMaybes <$> traverse (findRemovedStack scope) paths
+
+findRemovedStack
+  :: (MonadUnliftIO m, MonadResource m, MonadReader env m, HasAwsEnv env)
+  => AwsScope
+  -> FilePath
+  -> m (Maybe Stack)
+findRemovedStack scope path = runMaybeT $ do
+  -- The filter is a full path to a specification in the current
+  -- account/region...
+  stackName <- hoistMaybe $ awsScopeSpecStackName scope path
+
+  -- that no longer exists...
+  guard . not =<< doesFileExist path
+
+  -- but the Stack it would point to does
+  MaybeT $ awsCloudFormationDescribeStackMaybe stackName
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
@@ -16,6 +16,7 @@
 import Stackctl.DirectoryOption (HasDirectoryOption)
 import Stackctl.FilterOption (HasFilterOption)
 import Stackctl.ParameterOption
+import Stackctl.RemovedStack
 import Stackctl.Spec.Changes.Format
 import Stackctl.Spec.Discover
 import Stackctl.StackSpec
@@ -63,6 +64,15 @@
   -- Clear file before starting, as we have to use append for each spec
   liftIO $ traverse_ (`T.writeFile` "") scoOutput
 
+  colors <- case scoOutput of
+    Nothing -> getColorsLogger
+    Just{} -> pure noColors
+
+  let
+    write formatted = case scoOutput of
+      Nothing -> pushLoggerLn formatted
+      Just p -> liftIO $ T.appendFile p $ formatted <> "\n"
+
   specs <- discoverSpecs
 
   for_ specs $ \spec -> do
@@ -74,15 +84,8 @@
           logError $ "Error creating ChangeSet" :# ["error" .= err]
           exitFailure
         Right mChangeSet -> do
-          colors <- case scoOutput of
-            Nothing -> getColorsLogger
-            Just{} -> pure noColors
-
-          let
-            name = pack $ stackSpecPathFilePath $ stackSpecSpecPath spec
-            formatted =
-              formatChangeSet colors scoOmitFull name scoFormat mChangeSet
+          let name = pack $ stackSpecPathFilePath $ stackSpecSpecPath spec
+          write $ formatChangeSet colors scoOmitFull name scoFormat mChangeSet
 
-          case scoOutput of
-            Nothing -> pushLoggerLn formatted
-            Just p -> liftIO $ T.appendFile p $ formatted <> "\n"
+  removed <- inferRemovedStacks
+  traverse_ (write . formatRemovedStack colors scoFormat) removed
diff --git a/src/Stackctl/Spec/Changes/Format.hs b/src/Stackctl/Spec/Changes/Format.hs
--- a/src/Stackctl/Spec/Changes/Format.hs
+++ b/src/Stackctl/Spec/Changes/Format.hs
@@ -4,6 +4,7 @@
   , OmitFull(..)
   , omitFullOption
   , formatChangeSet
+  , formatRemovedStack
   , formatTTY
   ) where
 
@@ -56,6 +57,12 @@
 formatChangeSet colors omitFull name = \case
   FormatTTY -> formatTTY colors name
   FormatPullRequest -> formatPullRequest omitFull name
+
+formatRemovedStack :: Colors -> Format -> Stack -> Text
+formatRemovedStack Colors {..} format stack = case format of
+  FormatTTY -> red "DELETE" <> " stack " <> cyan name
+  FormatPullRequest -> ":x: This PR will **delete** the stack `" <> name <> "`"
+  where name = stack ^. stack_stackName
 
 formatTTY :: Colors -> Text -> Maybe ChangeSet -> Text
 formatTTY colors@Colors {..} name mChangeSet = case (mChangeSet, rChanges) of
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
@@ -20,6 +20,7 @@
 import Stackctl.FilterOption (HasFilterOption)
 import Stackctl.ParameterOption
 import Stackctl.Prompt
+import Stackctl.RemovedStack
 import Stackctl.Spec.Changes.Format
 import Stackctl.Spec.Discover
 import Stackctl.StackSpec
@@ -31,6 +32,7 @@
   , sdoTags :: [Tag]
   , sdoSaveChangeSets :: Maybe FilePath
   , sdoDeployConfirmation :: DeployConfirmation
+  , sdoRemovals :: Bool
   , sdoClean :: Bool
   }
 
@@ -50,6 +52,10 @@
     (  long "no-confirm"
     <> help "Don't confirm changes before executing"
     )
+  <*> (not <$> switch
+    (  long "no-remove"
+    <> help "Don't delete removed Stacks"
+    ))
   <*> switch
     (  long "clean"
     <> help "Remove all changesets from Stack after deploy"
@@ -98,6 +104,35 @@
           runActions stackName PostDeploy $ stackSpecActions spec
           when sdoClean $ awsCloudFormationDeleteAllChangeSets stackName
 
+  when sdoRemovals $ do
+    removed <- inferRemovedStacks
+    traverse_ (deleteRemovedStack sdoDeployConfirmation) removed
+
+deleteRemovedStack
+  :: ( MonadMask m
+     , MonadResource m
+     , MonadLogger m
+     , MonadReader env m
+     , HasLogger env
+     , HasAwsEnv env
+     )
+  => DeployConfirmation
+  -> Stack
+  -> m ()
+deleteRemovedStack confirmation stack = do
+  withThreadContext ["stack" .= stackName] $ do
+    colors <- getColorsLogger
+    pushLoggerLn $ formatRemovedStack colors FormatTTY stack
+
+    case confirmation of
+      DeployWithConfirmation -> do
+        promptContinue
+        logInfo "Deleting Stack"
+      DeployWithoutConfirmation -> pure ()
+
+    deleteStack stackName
+  where stackName = StackName $ stack ^. stack_stackName
+
 data DeployConfirmation
   = DeployWithConfirmation
   | DeployWithoutConfirmation
@@ -130,11 +165,18 @@
         exitFailure
 
     logInfo "Deleting Stack"
-    result <- awsCloudFormationDeleteStack stackName
+    deleteStack stackName
 
-    case result of
-      StackDeleteSuccess -> logInfo $ prettyStackDeleteResult result :# []
-      StackDeleteFailure{} -> logWarn $ prettyStackDeleteResult result :# []
+deleteStack
+  :: (MonadResource m, MonadLogger m, MonadReader env m, HasAwsEnv env)
+  => StackName
+  -> m ()
+deleteStack stackName = do
+  result <- awsCloudFormationDeleteStack stackName
+
+  case result of
+    StackDeleteSuccess -> logInfo $ prettyStackDeleteResult result :# []
+    StackDeleteFailure{} -> logWarn $ prettyStackDeleteResult result :# []
 
 deployChangeSet
   :: ( MonadUnliftIO m
diff --git a/src/Stackctl/Spec/Discover.hs b/src/Stackctl/Spec/Discover.hs
--- a/src/Stackctl/Spec/Discover.hs
+++ b/src/Stackctl/Spec/Discover.hs
@@ -30,27 +30,8 @@
   => m [StackSpec]
 discoverSpecs = do
   dir <- unDirectoryOption <$> view directoryOptionL
-  scope@AwsScope {..} <- view awsScopeL
-  paths <- globRelativeTo
-    dir
-    [ compile
-    $ "stacks"
-    </> unpack (unAccountId awsAccountId)
-    <> ".*"
-    </> unpack (fromRegion awsRegion)
-    <> "**"
-    </> "*"
-    <.> "yaml"
-    , compile
-    $ "stacks"
-    </> "*."
-    <> unpack (unAccountId awsAccountId)
-    </> unpack (fromRegion awsRegion)
-    <> "**"
-    </> "*"
-    <.> "yaml"
-    ]
-
+  scope <- view awsScopeL
+  paths <- globRelativeTo dir $ awsScopeSpecPatterns scope
   filterOption <- view filterOptionL
 
   let
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.4.0.0
+version:         1.4.0.1
 license:         MIT
 license-file:    LICENSE
 copyright:       2022 Renaissance Learning Inc
@@ -41,6 +41,7 @@
         Stackctl.ParameterOption
         Stackctl.Prelude
         Stackctl.Prompt
+        Stackctl.RemovedStack
         Stackctl.Sort
         Stackctl.Spec.Capture
         Stackctl.Spec.Cat
@@ -111,6 +112,7 @@
         semigroups,
         text,
         time,
+        transformers,
         unliftio,
         unliftio-core,
         unordered-containers,
@@ -149,6 +151,7 @@
     hs-source-dirs:     test
     other-modules:
         Stackctl.AWS.CloudFormationSpec
+        Stackctl.AWS.ScopeSpec
         Stackctl.Config.RequiredVersionSpec
         Stackctl.ConfigSpec
         Stackctl.FilterOptionSpec
diff --git a/test/Stackctl/AWS/ScopeSpec.hs b/test/Stackctl/AWS/ScopeSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Stackctl/AWS/ScopeSpec.hs
@@ -0,0 +1,56 @@
+module Stackctl.AWS.ScopeSpec
+  ( spec
+  ) where
+
+import Stackctl.Prelude
+
+import Stackctl.AWS.CloudFormation
+import Stackctl.AWS.Core
+import Stackctl.AWS.Scope
+import Test.Hspec
+
+spec :: Spec
+spec = do
+  describe "awsScopeSpecStackName" $ do
+    let
+      scope = AwsScope
+        { awsAccountId = AccountId "123"
+        , awsAccountName = "testing"
+        , awsRegion = "us-east-1"
+        }
+
+    it "parses full paths to stacks in the current scope" $ do
+      awsScopeSpecStackName scope "stacks/123.testing/us-east-1/foo.yaml"
+        `shouldBe` Just (StackName "foo")
+
+    it "parses name.account style too" $ do
+      awsScopeSpecStackName scope "stacks/testing.123/us-east-1/foo.yaml"
+        `shouldBe` Just (StackName "foo")
+
+    it "handles sub-directories" $ do
+      awsScopeSpecStackName scope "stacks/123.testing/us-east-1/foo/bar.yaml"
+        `shouldBe` Just (StackName "foo-bar")
+
+    it "handles mismatched name" $ do
+      awsScopeSpecStackName scope "stacks/123.x/us-east-1/foo.yaml"
+        `shouldBe` Just (StackName "foo")
+
+    it "handles mismatched name in name.account style" $ do
+      awsScopeSpecStackName scope "stacks/x.123/us-east-1/foo.yaml"
+        `shouldBe` Just (StackName "foo")
+
+    it "avoids wrong region" $ do
+      awsScopeSpecStackName scope "stacks/123.testing/us-east-2/foo.yaml"
+        `shouldBe` Nothing
+
+    it "avoids arong account id" $ do
+      awsScopeSpecStackName scope "stacks/124.testing/us-east-1/foo.yaml"
+        `shouldBe` Nothing
+
+    it "requires a stacks/ prefix" $ do
+      awsScopeSpecStackName scope "123.testing/us-east-1/foo.yaml"
+        `shouldBe` Nothing
+
+    it "requires a .yaml suffix" $ do
+      awsScopeSpecStackName scope "stacks/123.testing/us-east-1/foo.yml"
+        `shouldBe` Nothing
