diff --git a/exec/HaliveMain.hs b/exec/HaliveMain.hs
--- a/exec/HaliveMain.hs
+++ b/exec/HaliveMain.hs
@@ -44,7 +44,15 @@
             -- , gscCompilationMode = Compiled
             , gscCompilationMode = Interpreted
             })
-    recompiler <- recompilerForExpression ghc mainFileName "main" True
+
+    let fileTypes = ["hs", "pd", "frag", "vert"]
+
+    recompiler <- recompilerWithConfig ghc RecompilerConfig
+        { rccWatchAll = Just (".", fileTypes)
+        , rccExpression = "main"
+        , rccFilePath = mainFileName
+        , rccCompileImmediately = True
+        }
 
     mainThreadId <- myThreadId
 
diff --git a/halive.cabal b/halive.cabal
--- a/halive.cabal
+++ b/halive.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                halive
-version:             0.1.1
+version:             0.1.2
 synopsis:            A live recompiler
 description:
   Live recompiler for Haskell
diff --git a/src/Halive/FileListener.hs b/src/Halive/FileListener.hs
--- a/src/Halive/FileListener.hs
+++ b/src/Halive/FileListener.hs
@@ -43,12 +43,12 @@
     Modified path _ -> path == fileName
     _               -> False
 
-eventListenerForFile :: (MonadIO m) => FilePath -> ShouldReadFile -> m FileEventListener
+eventListenerForFile :: MonadIO m => FilePath -> ShouldReadFile -> m FileEventListener
 eventListenerForFile fileName shouldReadFile = liftIO $ do
     eventChan        <- newTChanIO
     ignoreEventsNear <- newTVarIO Nothing
 
-    stopMVar <- forkEventListenerThread fileName shouldReadFile eventChan ignoreEventsNear
+    stopMVar <- forkFileListenerThread fileName shouldReadFile eventChan ignoreEventsNear
 
     return FileEventListener
         { felEventTChan = eventChan
@@ -56,15 +56,54 @@
         , felStopMVar = stopMVar
         }
 
-killFileEventListener :: (MonadIO m) => FileEventListener -> m ()
+eventListenerForDirectory :: MonadIO m => FilePath -> [String] -> m FileEventListener
+eventListenerForDirectory watchDirectory fileTypes = liftIO $ do
+    eventChan        <- newTChanIO
+    ignoreEventsNear <- newTVarIO Nothing
+
+    stopMVar <- forkDirectoryListenerThread watchDirectory fileTypes eventChan
+
+    return FileEventListener
+        { felEventTChan = eventChan
+        , felIgnoreNextEventsNear = ignoreEventsNear
+        , felStopMVar = stopMVar
+        }
+
+killFileEventListener :: MonadIO m => FileEventListener -> m ()
 killFileEventListener eventListener = liftIO $ putMVar (felStopMVar eventListener) ()
 
-forkEventListenerThread :: FilePath
-                        -> ShouldReadFile
-                        -> TChan (Either FSNotify.Event String)
-                        -> TVar (Maybe UTCTime)
-                        -> IO (MVar ())
-forkEventListenerThread fileName shouldReadFile eventChan ignoreEventsNear = do
+-- Pass a list like ["hs", "pd", "frag", "vert"] to match only those filetypes,
+-- or an empty list to match all
+modifiedWithExtensionPredicate :: [String] -> FSNotify.Event -> Bool
+modifiedWithExtensionPredicate fileTypes event = case event of
+    Modified path _ -> null fileTypes || drop 1 (takeExtension path) `elem` fileTypes
+    _               -> False
+
+forkDirectoryListenerThread :: FilePath
+                            -> [String]
+                            -> TChan (Either FSNotify.Event String)
+                            -> IO (MVar ())
+forkDirectoryListenerThread watchDirectory fileTypes eventChan = do
+    let predicate = modifiedWithExtensionPredicate fileTypes
+
+    -- Configures debounce time for fsnotify
+    let watchConfig = defaultConfig
+            { confDebounce = Debounce 0.1 }
+    stopMVar <- newEmptyMVar
+    _ <- forkIO . withManagerConf watchConfig $ \manager -> do
+
+        stop <- watchTree manager watchDirectory predicate $ \e -> do
+            writeTChanIO eventChan (Left e)
+        () <- takeMVar stopMVar
+        stop
+    return stopMVar
+
+forkFileListenerThread :: FilePath
+                       -> ShouldReadFile
+                       -> TChan (Either FSNotify.Event String)
+                       -> TVar (Maybe UTCTime)
+                       -> IO (MVar ())
+forkFileListenerThread fileName shouldReadFile eventChan ignoreEventsNear = do
     predicate        <- fileModifiedPredicate <$> canonicalizePath fileName
     -- If an ignore time is set, ignore file changes for the next 100 ms
     let ignoreTime = 0.1
diff --git a/src/Halive/Recompiler.hs b/src/Halive/Recompiler.hs
--- a/src/Halive/Recompiler.hs
+++ b/src/Halive/Recompiler.hs
@@ -78,22 +78,43 @@
                         -> String
                         -> Bool
                         -> m Recompiler
-recompilerForExpression ghcChan filePath expressionString compileOnce = liftIO $ do
+recompilerForExpression ghcChan filePath expressionString compileImmediately =
+    recompilerWithConfig ghcChan RecompilerConfig
+        { rccWatchAll = Nothing
+        , rccExpression = expressionString
+        , rccFilePath = filePath
+        , rccCompileImmediately = compileImmediately
+        }
+
+data RecompilerConfig = RecompilerConfig
+    { rccWatchAll :: Maybe (FilePath, [String]) -- if Nothing, just watch given file
+    , rccExpression :: String
+    , rccFilePath :: FilePath
+    , rccCompileImmediately :: Bool
+    }
+
+recompilerWithConfig :: MonadIO m
+                     => TChan CompilationRequest
+                     -> RecompilerConfig
+                     -> m Recompiler
+recompilerWithConfig ghcChan RecompilerConfig{..} = liftIO $ do
     resultTChan <- newTChanIO
     let compilationRequest = CompilationRequest
-            { crFilePath         = filePath
-            , crExpressionString = expressionString
+            { crFilePath         = rccFilePath
+            , crExpressionString = rccExpression
             , crResultTChan      = resultTChan
             , crFileContents     = Nothing
             }
 
 
     -- Compile for the first time immediately
-    when compileOnce $
+    when rccCompileImmediately $
         writeTChanIO ghcChan compilationRequest
 
     -- Recompile on file event notifications
-    fileEventListener <- eventListenerForFile filePath JustReportEvents
+    fileEventListener <- case rccWatchAll of 
+        Nothing -> eventListenerForFile rccFilePath JustReportEvents
+        Just (watchDir, fileTypes) -> eventListenerForDirectory watchDir fileTypes
     listenerThread <- forkIO . forever $ do
         _ <- readFileEvent fileEventListener
         writeTChanIO ghcChan compilationRequest
