diff --git a/hsdev.cabal b/hsdev.cabal
--- a/hsdev.cabal
+++ b/hsdev.cabal
@@ -2,7 +2,7 @@
 --  see http://haskell.org/cabal/users-guide/
 
 name:                hsdev
-version:             0.1.6.6
+version:             0.1.7.0
 synopsis:            Haskell development library and tool with support of autocompletion, symbol info, go to declaration, find references etc.
 description:
   Haskell development library and tool with support of autocompletion, symbol info, go to declaration, find references, hayoo search etc.
@@ -28,12 +28,12 @@
     Control.Concurrent.Worker
     Control.Concurrent.Util
     Data.Async
+    Data.Deps
     Data.Group
     Data.Help
     Data.Lisp
     Data.Maybe.JustIf
     HsDev
-    HsDev.Cabal
     HsDev.Cache
     HsDev.Cache.Structured
     HsDev.Client.Commands
@@ -44,6 +44,7 @@
     HsDev.Database.Update.Types
     HsDev.Display
     HsDev.Inspect
+    HsDev.PackageDb
     HsDev.Project
     HsDev.Scan
     HsDev.Scan.Browse
@@ -51,6 +52,8 @@
     HsDev.Server.Commands
     HsDev.Server.Message
     HsDev.Server.Types
+    HsDev.Sandbox
+    HsDev.Stack
     HsDev.Symbols
     HsDev.Symbols.Class
     HsDev.Symbols.Location
diff --git a/src/Data/Deps.hs b/src/Data/Deps.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Deps.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
+
+module Data.Deps (
+	Deps(..), depsMap,
+	mapDeps,
+	dep, deps,
+	inverse, flatten
+	) where
+
+import Control.Lens
+import Control.Monad.State
+import Data.List (nub)
+import Data.Map (Map)
+import qualified Data.Map as M
+import Data.Maybe (fromMaybe)
+
+-- | Dependency map
+data Deps a = Deps {
+	_depsMap :: Map a [a] }
+
+depsMap :: (Ord a, Ord b) => Lens (Deps a) (Deps b) (Map a [a]) (Map b [b])
+depsMap = lens _depsMap (const Deps)
+
+instance Ord a => Monoid (Deps a) where
+	mempty = Deps mempty
+	mappend (Deps l) (Deps r) = Deps $ M.unionWith nubConcat l r
+
+type instance Index (Deps a) = a
+type instance IxValue (Deps a) = [a]
+
+instance Ord a => Ixed (Deps a) where
+	ix k = depsMap . ix k
+
+instance Ord a => At (Deps a) where
+	at k = depsMap . at k
+
+mapDeps :: (Ord a, Ord b) => (a -> b) -> Deps a -> Deps b
+mapDeps f = Deps . M.mapKeys f . M.map (map f) . _depsMap
+
+-- | Make single dependency
+dep :: Ord a => a -> a -> Deps a
+dep x y = deps x [y]
+
+-- | Make dependency for one target, note that order of dependencies is matter
+deps :: Ord a => a -> [a] -> Deps a
+deps x ys = Deps $ M.singleton x ys
+
+-- | Inverse dependencies, i.e. make map where keys are dependencies and elements are targets depends on it
+inverse :: Ord a => Deps a -> Deps a
+inverse = mconcat . map (uncurry dep) . concatMap inverse' . M.toList . _depsMap where
+	inverse' :: (a, [a]) -> [(a, a)]
+	inverse' (m, ds) = zip ds (repeat m)
+
+-- | Flatten dependencies so that there will be no indirect dependencies
+flatten :: Ord a => Deps a -> Deps a
+flatten (Deps ds) = flip execState mempty . mapM_ flatten' . M.keys $ ds where
+	-- flatten' :: a -> State (Deps a) [a]
+	flatten' n = do
+		d <- gets (M.lookup n . _depsMap)
+		case d of
+			Just d' -> return d'
+			Nothing -> do
+				let
+					deps' = fromMaybe [] $ M.lookup n ds
+				d'' <- (nub . concat . (++ [deps'])) <$> mapM flatten' deps'
+				modify $ mappend (deps n d'')
+				return d''
+
+nubConcat :: Ord a => [a] -> [a] -> [a]
+nubConcat xs ys = nub $ xs ++ ys
diff --git a/src/HsDev/Cabal.hs b/src/HsDev/Cabal.hs
deleted file mode 100644
--- a/src/HsDev/Cabal.hs
+++ /dev/null
@@ -1,90 +0,0 @@
-{-# LANGUAGE OverloadedStrings, MultiWayIf, FlexibleContexts #-}
-
-module HsDev.Cabal (
-	Cabal(..), sandbox,
-	isPackageDb, findPackageDb, locateSandbox, getSandbox, searchSandbox,
-	cabalOpt
-	) where
-
-import Control.Applicative
-import Control.DeepSeq (NFData(..))
-import Control.Monad.Except
-import Data.Aeson
-import Data.List
-import System.Directory
-import System.FilePath
-
-import HsDev.Util (searchPath, liftE)
-
--- | Cabal or sandbox
-data Cabal = Cabal | Sandbox FilePath deriving (Eq, Ord)
-
--- | Get sandbox
-sandbox :: Cabal -> Maybe FilePath
-sandbox Cabal = Nothing
-sandbox (Sandbox f) = Just f
-
-instance NFData Cabal where
-	rnf Cabal = ()
-	rnf (Sandbox p) = rnf p
-
-instance Show Cabal where
-	show Cabal = "<cabal>"
-	show (Sandbox p) = p
-
-instance ToJSON Cabal where
-	toJSON Cabal = toJSON ("cabal" :: String)
-	toJSON (Sandbox p) = toJSON $ object [
-		"sandbox" .= p]
-
-instance FromJSON Cabal where
-	parseJSON v = cabalP v <|> sandboxP v where
-		cabalP = withText "cabal" cabalText where
-			cabalText "cabal" = return Cabal
-			cabalText _ = fail "Unknown cabal string"
-		sandboxP = withObject "sandbox" sandboxPath where
-			sandboxPath obj = fmap Sandbox $ obj .: "sandbox"
-
--- | Is -package-db file
-isPackageDb :: FilePath -> Bool
-isPackageDb p = cabalDev p || cabalSandbox p where
-	cabalDev dir = "packages-" `isPrefixOf` dir && ".conf" `isSuffixOf` dir
-	cabalSandbox dir = "-packages.conf.d" `isSuffixOf` dir
-
--- | Is .cabal-sandbox
-cabalSandboxDir :: FilePath -> Bool
-cabalSandboxDir p = takeFileName p == ".cabal-sandbox"
-
--- | Find -package-db path for sandbox directory or package-db file itself
-findPackageDb :: FilePath -> IO (Maybe FilePath)
-findPackageDb sand = do
-	sand' <- canonicalizePath sand
-	isDir <- doesDirectoryExist sand'
-	if
-		| isDir && isPackageDb sand' -> return $ Just sand'
-		| isDir -> do
-			cts <- getDirectoryContents sand'
-			(dir', cts') <- case find cabalSandboxDir cts of
-				Nothing -> return (sand', cts)
-				Just sbox -> (,) <$> pure (sand' </> sbox) <*> getDirectoryContents (sand' </> sbox)
-			return $ fmap (dir' </>) $ find isPackageDb cts'
-		| otherwise -> return Nothing
-
--- | Create sandbox by directory or package-db file
-locateSandbox :: FilePath -> ExceptT String IO Cabal
-locateSandbox p = liftE (findPackageDb p) >>= maybe
-	(throwError $ "Can't locate package-db in sandbox: " ++ p)
-	(return . Sandbox)
-
--- | Try find sandbox by parent directory
-getSandbox :: FilePath -> IO Cabal
-getSandbox = liftM (either (const Cabal) id) . runExceptT . locateSandbox
-
--- | Search sandbox
-searchSandbox :: FilePath -> IO Cabal
-searchSandbox p = runExceptT (searchPath p locateSandbox) >>= either (const $ return Cabal) return
-
--- | Cabal ghc option
-cabalOpt :: Cabal -> [String]
-cabalOpt Cabal = []
-cabalOpt (Sandbox p) = ["-package-db " ++ p]
diff --git a/src/HsDev/Cache.hs b/src/HsDev/Cache.hs
--- a/src/HsDev/Cache.hs
+++ b/src/HsDev/Cache.hs
@@ -2,37 +2,49 @@
 
 module HsDev.Cache (
 	escapePath,
-	cabalCache,
+	versionCache,
+	packageDbCache,
 	projectCache,
 	standaloneCache,
 	dump,
 	load,
+	writeVersion,
+	readVersion,
 
 	-- * Reexports
 	Database
 	) where
 
 import Control.DeepSeq (force)
+import Control.Exception
 import Control.Lens (view)
-import Data.Aeson (eitherDecode)
+import Data.Aeson (encode, eitherDecode)
 import Data.Aeson.Encode.Pretty (encodePretty)
 import qualified Data.ByteString.Lazy.Char8 as BS
 import Data.Char (isAlphaNum)
 import Data.List (intercalate)
 import System.FilePath
+import Text.Read (readMaybe)
 
-import HsDev.Symbols (Cabal(..))
+import HsDev.PackageDb
 import HsDev.Project
 import HsDev.Database (Database)
+import HsDev.Version
+import HsDev.Util (split, version)
 
 -- | Escape path
 escapePath :: FilePath -> FilePath
 escapePath = intercalate "." . map (filter isAlphaNum) . splitDirectories
 
+-- | Name of cache for version
+versionCache :: FilePath
+versionCache = "version" <.> "json"
+
 -- | Name of cache for cabal
-cabalCache :: Cabal -> FilePath
-cabalCache Cabal = "cabal" <.> "json"
-cabalCache (Sandbox p) = escapePath p <.> "json"
+packageDbCache :: PackageDb -> FilePath
+packageDbCache GlobalDb = "global" <.> "json"
+packageDbCache UserDb = "user" <.> "json"
+packageDbCache (PackageDb p) = escapePath p <.> "json"
 
 -- | Name of cache for projects
 projectCache :: Project -> FilePath
@@ -48,6 +60,22 @@
 
 -- | Load database from file, strict
 load :: FilePath -> IO (Either String Database)
-load file = do
+load file = handle onIO $ do
 	cts <- BS.readFile file
 	return $ force $ eitherDecode cts
+	where
+		onIO :: IOException -> IO (Either String Database)
+		onIO _ = return $ Left $ "IO exception while reading cache from " ++ file
+
+-- | Write version
+writeVersion :: FilePath -> IO ()
+writeVersion file = BS.writeFile file $ encode version
+
+-- | Read version
+readVersion :: FilePath -> IO (Maybe [Int])
+readVersion file = handle onIO $ do
+	cts <- BS.readFile file
+	return $ either (const Nothing) id $ eitherDecode cts
+	where
+		onIO :: IOException -> IO (Maybe [Int])
+		onIO _ = return Nothing
diff --git a/src/HsDev/Cache/Structured.hs b/src/HsDev/Cache/Structured.hs
--- a/src/HsDev/Cache/Structured.hs
+++ b/src/HsDev/Cache/Structured.hs
@@ -1,6 +1,6 @@
 module HsDev.Cache.Structured (
 	dump, load,
-	loadCabal, loadProject, loadFiles
+	loadPackageDb, loadProject, loadFiles
 	) where
 
 import Control.DeepSeq
@@ -22,8 +22,8 @@
 dump dir db = do
 	createDirectoryIfMissing True (dir </> "cabal")
 	createDirectoryIfMissing True (dir </> "projects")
-	forM_ (M.assocs $ structuredCabals db) $ \(c, cdb) -> Cache.dump
-		(dir </> "cabal" </> Cache.cabalCache c)
+	forM_ (M.assocs $ structuredPackageDbs db) $ \(c, cdb) -> Cache.dump
+		(dir </> "cabal" </> Cache.packageDbCache c)
 		cdb
 	forM_ (M.assocs $ structuredProjects db) $ \(p, pdb) -> Cache.dump
 		(dir </> "projects" </> Cache.projectCache (project p))
@@ -38,8 +38,8 @@
 
 -- | Load all cache
 load :: FilePath -> IO (Either String Structured)
-load dir = runExceptT $ join $ either throwError return <$> (structured <$> loadCabals <*> loadProjects <*> loadStandaloneFiles) where
-	loadCabals = loadDir (dir </> "cabal")
+load dir = runExceptT $ join $ either throwError return <$> (structured <$> loadPackageDbs <*> loadProjects <*> loadStandaloneFiles) where
+	loadPackageDbs = loadDir (dir </> "cabal")
 	loadProjects = loadDir (dir </> "projects")
 	loadStandaloneFiles = ExceptT $ Cache.load (dir </> Cache.standaloneCache)
 
@@ -52,9 +52,9 @@
 loadData = liftExceptionM . ExceptT . Cache.load
 
 -- | Load cabal from cache
-loadCabal :: Cabal -> FilePath -> ExceptT String IO Structured
-loadCabal c dir = do
-	dat <- loadData (dir </> "cabal" </> Cache.cabalCache c)
+loadPackageDb :: PackageDb -> FilePath -> ExceptT String IO Structured
+loadPackageDb c dir = do
+	dat <- loadData (dir </> "cabal" </> Cache.packageDbCache c)
 	ExceptT $ return $ structured [dat] [] mempty
 
 -- | Load project from cache
diff --git a/src/HsDev/Client/Commands.hs b/src/HsDev/Client/Commands.hs
--- a/src/HsDev/Client/Commands.hs
+++ b/src/HsDev/Client/Commands.hs
@@ -12,7 +12,7 @@
 import Control.Monad
 import Control.Monad.Except
 import Control.Monad.Reader
-import Control.Monad.State (gets)
+import qualified Control.Monad.State as State
 import Control.Monad.Catch (try, SomeException(..))
 import Data.Aeson hiding (Result, Error)
 import Data.List
@@ -37,6 +37,9 @@
 import qualified HsDev.Database.Async as DB
 import HsDev.Server.Message as M
 import HsDev.Server.Types
+import HsDev.Sandbox hiding (findSandbox)
+import qualified HsDev.Sandbox as S (findSandbox)
+import HsDev.Stack
 import HsDev.Symbols
 import HsDev.Symbols.Resolve (resolveOne, scopeModule, exportsModule)
 import HsDev.Symbols.Util
@@ -52,6 +55,8 @@
 import HsDev.Util
 import HsDev.Watcher
 
+import qualified HsDev.Scan as Scan
+import qualified HsDev.Scan.Browse as Scan
 import qualified HsDev.Database.Update as Update
 
 runClient :: (ToJSON a, ServerMonadBase m) => CommandOptions -> ClientM m a -> ServerM m Result
@@ -75,14 +80,15 @@
 	updateData (AddedDatabase db) = toValue $ serverUpdateDB db
 	updateData (AddedModule m) = toValue $ serverUpdateDB $ fromModule m
 	updateData (AddedProject p) = toValue $ serverUpdateDB $ fromProject p
-runCommand (Scan projs cabals fs paths' fcts ghcs' docs' infer') = toValue $ do
-	sboxes <- getSandboxes cabals
+runCommand (Scan projs cabal sboxes fs paths' fcts ghcs' docs' infer') = toValue $ do
+	sboxes' <- getSandboxes sboxes
 	updateProcess (Update.UpdateOptions [] ghcs' docs' infer') $ concat [
 		map (\(FileContents f cts) -> Update.scanFileContents ghcs' f (Just cts)) fcts,
 		map (Update.scanProject ghcs') projs,
 		map (Update.scanFile ghcs') fs,
 		map (Update.scanDirectory ghcs') paths',
-		map (Update.scanCabal ghcs') sboxes]
+		if cabal then [Update.scanCabal ghcs'] else [],
+		map (Update.scanSandbox ghcs') sboxes']
 runCommand (RefineDocs projs fs ms) = toValue $ do
 	projects <- traverse findProject projs
 	dbval <- getDb
@@ -103,22 +109,45 @@
 			map inModule ms]
 		mods = selectModules (filters . view moduleId) dbval
 	updateProcess (Update.UpdateOptions [] [] False False) [Update.inferModTypes $ map (getInspected dbval) mods]
-runCommand (Remove projs cabals files) = toValue $ do
+runCommand (Remove projs cabal sboxes files) = toValue $ do
 	db <- askSession sessionDatabase
 	dbval <- getDb
 	w <- askSession sessionWatcher
 	projects <- traverse findProject projs
+	sboxes' <- getSandboxes sboxes
 	forM_ projects $ \proj -> do
 		DB.clear db (return $ projectDB proj dbval)
 		liftIO $ unwatchProject w proj
-	forM_ cabals $ \cabal -> do
-		DB.clear db (return $ cabalDB cabal dbval)
-		liftIO $ unwatchSandbox w cabal
+	dbPDbs <- liftIO $ mapM restorePackageDbStack $ databasePackageDbs dbval
+	flip State.evalStateT dbPDbs $ do
+		when cabal $ removePackageDbStack userDb
+		forM_ sboxes' $ \sbox -> do
+			pdbs <- lift $ mapCommandIO $ sandboxPackageDbStack sbox
+			removePackageDbStack pdbs
 	forM_ files $ \file -> do
 		DB.clear db (return $ filterDB (inFile file) (const False) dbval)
 		let
 			mloc = fmap (view moduleLocation) $ lookupFile file dbval
 		maybe (return ()) (liftIO . unwatchModule w) mloc
+	where
+		-- We can safely remove package-db from db iff doesn't used by some of other package-dbs
+		-- For example, we can't remove global-db if there are any other package-dbs, because all of them uses global-db
+		-- We also can't remove stack snapshot package-db if there are some local package-db not yet removed
+		canRemove pdbs = do
+			from <- State.get
+			return $ null $ filter (pdbs `isSubStack`) $ delete pdbs from
+		-- Remove top of package-db stack if possible
+		removePackageDb pdbs = do
+			db <- lift $ askSession sessionDatabase
+			dbval <- lift getDb
+			w <- lift $ askSession sessionWatcher
+			can <- canRemove pdbs
+			when can $ do
+				State.modify (delete pdbs)
+				DB.clear db (return $ packageDbDB (topPackageDb pdbs) dbval)
+				liftIO $ unwatchPackageDb w $ topPackageDb pdbs
+		-- Remove package-db stack when possible
+		removePackageDbStack = mapM_ removePackageDb . packageDbStacks
 runCommand RemoveAll = toValue $ do
 	db <- askSession sessionDatabase
 	liftIO $ A.modifyAsync db A.Clear
@@ -131,7 +160,7 @@
 	return $ map (view moduleId) $ newestPackage $ selectModules (filter' . view moduleId) dbval
 runCommand InfoPackages = toValue $ (ordNub . sort . 	mapMaybe (preview (moduleLocation . modulePackage . _Just)) . allModules) <$> getDb
 runCommand InfoProjects = toValue $ (toList . databaseProjects) <$> getDb
-runCommand InfoSandboxes = toValue $ (ordNub . sort . mapMaybe (cabalOf . view moduleId) . allModules) <$> getDb
+runCommand InfoSandboxes = toValue $ databasePackageDbs <$> getDb
 runCommand (InfoSymbol sq fs locals') = toValue $ do
 	dbval <- liftM (localsDatabase locals') $ getDb
 	filter' <- targetFilters fs
@@ -141,39 +170,32 @@
 	filter' <- targetFilters fs
 	return $ newestPackage $ filterMatch sq $ filter (filter' . view moduleId) $ allModules dbval
 runCommand (InfoResolve fpath exports) = toValue $ do
-	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
+	dbval <- getSDb fpath
 	let
-		cabaldb = filterDB (restrictCabal cabal) (const True) dbval
 		getScope
 			| exports = exportsModule
 			| otherwise = scopeModule
 	case lookupFile fpath dbval of
 		Nothing -> commandError "File not found" []
-		Just m -> return $ getScope $ resolveOne cabaldb m
+		Just m -> return $ getScope $ resolveOne dbval m
 runCommand (InfoProject (Left projName)) = toValue $ findProject projName
 runCommand (InfoProject (Right projPath)) = toValue $ liftIO $ searchProject projPath
 runCommand (InfoSandbox sandbox') = toValue $ liftIO $ searchSandbox sandbox'
 runCommand (Lookup nm fpath) = toValue $ do
-	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
-	mapCommandIO $ lookupSymbol dbval cabal fpath nm
+	dbval <- getSDb fpath
+	mapCommandIO $ lookupSymbol dbval fpath nm
 runCommand (Whois nm fpath) = toValue $ do
-	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
-	mapCommandIO $ whois dbval cabal fpath nm
+	dbval <- getSDb fpath
+	mapCommandIO $ whois dbval fpath nm
 runCommand (ResolveScopeModules sq fpath) = toValue $ do
-	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
-	liftM (filterMatch sq . map (view moduleId)) $ mapCommandIO $ scopeModules dbval cabal fpath
+	dbval <- getSDb fpath
+	liftM (filterMatch sq . map (view moduleId)) $ mapCommandIO $ scopeModules dbval fpath
 runCommand (ResolveScope sq global fpath) = toValue $ do
-	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
-	liftM (filterMatch sq) $ mapCommandIO $ scope dbval cabal fpath global
+	dbval <- getSDb fpath
+	liftM (filterMatch sq) $ mapCommandIO $ scope dbval fpath global
 runCommand (Complete input wide fpath) = toValue $ do
-	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
-	mapCommandIO $ completions dbval cabal fpath input wide
+	dbval <- getSDb fpath
+	mapCommandIO $ completions dbval fpath input wide
 runCommand (Hayoo hq p ps) = toValue $ liftM concat $ forM [p .. p + pred ps] $ \i -> liftM
 	(mapMaybe Hayoo.hayooAsDeclaration . Hayoo.resultResult) $
 	mapCommandIO $ Hayoo.hayoo hq (Just i)
@@ -182,67 +204,68 @@
 	mapCommandIO $ liftM2 (++)
 		(liftM concat $ mapM HLint.hlintFile fs)
 		(liftM concat $ mapM (\(FileContents f c) -> HLint.hlintSource f c) fcts)
-runCommand (Check fs fcts ghcs') = toValue $ do
-	db <- getDb
+runCommand (Check fs fcts ghcs') = toValue $ Log.scope "check" $ do
+	dbval <- getDb
 	ghc <- askSession sessionGhc
 	liftIO $ restartWorker ghc
 	let
-		checkSome file fn = do
-			cabal <- liftIO $ getSandbox file
+		checkSome file fn = Log.scope "checkSome" $ do
+			pdbs <- liftIO $ searchPackageDbStack file
 			m <- maybe
 				(commandError_ $ "File '{}' not found" ~~ file)
 				return
-				(lookupFile file db)
+				(lookupFile file dbval)
 			notes <- inWorkerWith (commandError_ . show) ghc
-				(runExceptT $ fn cabal m)
+				(runExceptT $ fn pdbs m)
 			either commandError_ return notes
 	liftM concat $ mapM (uncurry checkSome) $
 		[(f, Check.checkFile ghcs') | f <- fs] ++
-		[(f, \cabal m -> Check.checkSource ghcs' cabal m src) | FileContents f src <- fcts]
+		[(f, \pdbs m -> Check.checkSource ghcs' pdbs m src) | FileContents f src <- fcts]
 runCommand (CheckLint fs fcts ghcs') = toValue $ do
-	db <- getDb
+	dbval <- getDb
 	ghc <- askSession sessionGhc
 	liftIO $ restartWorker ghc
 	let
 		checkSome file fn = do
-			cabal <- liftIO $ getSandbox file
+			pdbs <- liftIO $ searchPackageDbStack file
 			m <- maybe
 				(commandError_ $ "File '" ++ file ++ "' not found")
 				return
-				(lookupFile file db)
+				(lookupFile file dbval)
 			notes <- inWorkerWith (commandError_ . show) ghc
-				(runExceptT $ fn cabal m)
+				(runExceptT $ fn pdbs m)
 			either commandError_ return notes
 	checkMsgs <- liftM concat $ mapM (uncurry checkSome) $
 		[(f, Check.checkFile ghcs') | f <- fs] ++
-		[(f, \cabal m -> Check.checkSource ghcs' cabal m src) | FileContents f src <- fcts]
+		[(f, \pdbs m -> Check.checkSource ghcs' pdbs m src) | FileContents f src <- fcts]
 	lintMsgs <- mapCommandIO $ liftM2 (++)
 		(liftM concat $ mapM HLint.hlintFile fs)
 		(liftM concat $ mapM (\(FileContents f src) -> HLint.hlintSource f src) fcts)
 	return $ checkMsgs ++ lintMsgs
 runCommand (Types fs fcts ghcs') = toValue $ do
-	db <- getDb
+	dbval <- getDb
 	ghc <- askSession sessionGhc
 	let
 		cts = [(f, Nothing) | f <- fs] ++ [(f, Just src) | FileContents f src <- fcts]
 	liftM concat $ forM cts $ \(file, msrc) -> do
-		cabal <- liftIO $ getSandbox file
+		pdbs <- liftIO $ searchPackageDbStack file
 		m <- maybe
 			(commandError_ $ "File '" ++ file ++ "' not found")
 			return
-			(lookupFile file db)
+			(lookupFile file dbval)
 		notes <- inWorkerWith (commandError_ . show) ghc
-			(runExceptT $ Types.fileTypes ghcs' cabal m msrc)
+			(runExceptT $ Types.fileTypes ghcs' pdbs m msrc)
 		either commandError_ return notes
 runCommand (GhcMod GhcModLang) = toValue $ mapCommandIO $ GhcMod.langs
 runCommand (GhcMod GhcModFlags) = toValue $ mapCommandIO $ GhcMod.flags
 runCommand (GhcMod (GhcModType (Position line column) fpath ghcs')) = toValue $ do
 	ghcmod <- askSession sessionGhcMod
 	dbval <- getDb
-	cabal <- liftIO $ getSandbox fpath
+	pdbs <- liftIO $ searchPackageDbStack fpath
+	pkgs <- mapCommandIO $ Scan.browsePackages ghcs' pdbs
 	(fpath', m', _) <- mapCommandIO $ fileCtx dbval fpath
 	mapCommandIO $ GhcMod.waitMultiGhcMod ghcmod fpath' $
-		GhcMod.typeOf (ghcs' ++ moduleOpts (allPackages dbval) m') cabal fpath' line column
+		GhcMod.typeOf (ghcs' ++ moduleOpts pkgs m') pdbs fpath' line column
 runCommand (GhcMod (GhcModLint fs hlints')) = toValue $ do
 	ghcmod <- askSession sessionGhcMod
 	mapCommandIO $ liftM concat $ forM fs $ \file ->
@@ -253,19 +276,21 @@
 	dbval <- getDb
 	mapCommandIO $ liftM concat $ forM fs $ \file -> do
 		mproj <- liftIO $ locateProject file
-		cabal <- liftIO $ getSandbox file
+		pdbs <- liftIO $ searchPackageDbStack file
+		pkgs <- Scan.browsePackages ghcs' pdbs
 		(_, m', _) <- fileCtx dbval file
 		GhcMod.waitMultiGhcMod ghcmod file $
-			GhcMod.check (ghcs' ++ moduleOpts (allPackages dbval) m') cabal [file] mproj
+			GhcMod.check (ghcs' ++ moduleOpts pkgs m') pdbs [file] mproj
 runCommand (GhcMod (GhcModCheckLint fs ghcs' hlints')) = toValue $ do
 	ghcmod <- askSession sessionGhcMod
 	dbval <- getDb
 	mapCommandIO $ liftM concat $ forM fs $ \file -> do
 		mproj <- liftIO $ locateProject file
-		cabal <- liftIO $ getSandbox file
+		pdbs <- liftIO $ searchPackageDbStack file
+		pkgs <- Scan.browsePackages ghcs' pdbs
 		(_, m', _) <- fileCtx dbval file
 		GhcMod.waitMultiGhcMod ghcmod file $ do
-			checked <- GhcMod.check (ghcs' ++ moduleOpts (allPackages dbval) m') cabal [file] mproj
+			checked <- GhcMod.check (ghcs' ++ moduleOpts pkgs m') pdbs [file] mproj
 			linted <- GhcMod.lint hlints' file
 			return $ checked ++ linted
 runCommand (AutoFix (AutoFixShow ns)) = toValue $ return $ AutoFix.corrections ns
@@ -275,7 +300,7 @@
 		doFix :: FilePath -> String -> ([Tools.Note AutoFix.Correction], String)
 		doFix file cts = AutoFix.edit cts fUpCorrs $ do
 			AutoFix.autoFix fCorrs
-			gets (view AutoFix.regions)
+			State.gets (view AutoFix.regions)
 			where
 				findCorrs :: FilePath -> [Tools.Note AutoFix.Correction] -> [Tools.Note AutoFix.Correction]
 				findCorrs f = filter ((== Just f) . preview (Tools.noteSource . moduleFile))
@@ -313,18 +338,15 @@
 	TargetFile file -> return $ inFile file
 	TargetModule mname -> return $ inModule mname
 	TargetDepsOf dep -> liftM inDeps $ findDep dep
-	TargetCabal cabal -> liftM inCabal $ findSandbox cabal
+	TargetPackageDb pdb -> return $ inPackageDb pdb
+	TargetCabal -> return $ inPackageDbStack userDb
+	TargetSandbox sbox -> liftM inPackageDbStack $ findSandbox sbox >>= mapCommandIO . sandboxPackageDbStack
 	TargetPackage pack -> return $ inPackage pack
 	TargetSourced -> return byFile
 	TargetStandalone -> return standalone
 
 -- Helper functions
 
--- | Find sandbox by path
-findSandbox :: CommandMonad m => Cabal -> m Cabal
-findSandbox Cabal = return Cabal
-findSandbox (Sandbox f) = (findPath >=> mapCommandErrorStr . liftIO . getSandbox) f
-
 -- | Canonicalize paths
 findPath :: (CommandMonad m, Paths a) => a -> m a
 findPath = paths findPath' where
@@ -333,9 +355,19 @@
 		r <- commandRoot
 		liftIO $ canonicalizePath (normalise $ if isRelative f then r </> f else f)
 
+-- | Find sandbox by path
+findSandbox :: (CommandMonad m, Functor m) => FilePath -> m Sandbox
+findSandbox fpath = do
+	fpath' <- findPath fpath
+	sbox <- liftIO $ S.findSandbox fpath'
+	maybe
+		(commandError ("Sandbox {} not found" ~~ fpath') ["sandbox" .= fpath'])
+		return
+		sbox
+
 -- | Get list of enumerated sandboxes
-getSandboxes :: (CommandMonad m, Functor m) => [Cabal] -> m [Cabal]
-getSandboxes = traverse findSandbox
+getSandboxes :: (CommandMonad m, Functor m) => [FilePath] -> m [Sandbox]
+getSandboxes = traverse (findPath >=> findSandbox)
 
 -- | Find project by name or path
 findProject :: CommandMonad m => String -> m Project
@@ -353,7 +385,7 @@
 			| otherwise = p </> (takeBaseName p <.> "cabal")
 
 -- | Find dependency: it may be source, project file or project name, also returns sandbox found
-findDep :: CommandMonad m => String -> m (Project, Maybe FilePath, Cabal)
+findDep :: CommandMonad m => String -> m (Project, Maybe FilePath, PackageDbStack)
 findDep depName = do
 	depPath <- findPath depName
 	proj <- msum [
@@ -367,13 +399,13 @@
 		src
 			| takeExtension depPath == ".hs" = Just depPath
 			| otherwise = Nothing
-	sbox <- liftIO $ searchSandbox $ view projectPath proj
-	return (proj, src, sbox)
+	pdbs <- liftIO $ searchPackageDbStack $ view projectPath proj
+	return (proj, src, pdbs)
 
 -- FIXME: Doesn't work for file without project
 -- | Check if project or source depends from this module
-inDeps :: (Project, Maybe FilePath, Cabal) -> ModuleId -> Bool
-inDeps (proj, src, cabal) = liftM2 (&&) (restrictCabal cabal) deps' where
+inDeps :: (Project, Maybe FilePath, PackageDbStack) -> ModuleId -> Bool
+inDeps (proj, src, pdbs) = liftM2 (&&) (restrictPackageDbStack pdbs) deps' where
 	deps' = case src of
 		Nothing -> inDepsOfProject proj
 		Just src' -> inDepsOfFile proj src'
@@ -386,6 +418,13 @@
 -- | Get actual DB state
 getDb :: SessionMonad m => m Database
 getDb = askSession sessionDatabase >>= liftIO . DB.readAsync
+
+-- | Get DB with filtered sanxboxes for file
+getSDb :: SessionMonad m => FilePath -> m Database
+getSDb fpath = do
+	dbval <- getDb
+	pdbs <- liftIO $ searchPackageDbStack fpath
+	return $ filterDB (restrictPackageDbStack pdbs) (const True) dbval
 
 mapCommandErrorStr :: CommandMonad m => ExceptT String m a -> m a
 mapCommandErrorStr act = runExceptT act >>= either commandError_ return
diff --git a/src/HsDev/Commands.hs b/src/HsDev/Commands.hs
--- a/src/HsDev/Commands.hs
+++ b/src/HsDev/Commands.hs
@@ -11,7 +11,7 @@
 	moduleCompletions,
 
 	-- * Filters
-	checkModule, checkDeclaration, restrictCabal, visibleFrom,
+	checkModule, checkDeclaration, restrictPackageDb, restrictPackageDbStack, visibleFrom,
 	splitIdentifier,
 
 	-- * Helpers
@@ -71,12 +71,11 @@
 		refineProject db p'
 
 -- | Lookup visible within project/cabal symbol
-lookupSymbol :: Database -> Cabal -> FilePath -> String -> ExceptT String IO [ModuleDeclaration]
-lookupSymbol db cabal file ident = do
+lookupSymbol :: Database -> FilePath -> String -> ExceptT String IO [ModuleDeclaration]
+lookupSymbol db file ident = do
 	(_, mthis, mproj) <- fileCtx db file
 	liftM
 		(filter $ checkModule $ allOf [
-			restrictCabal cabal,
 			visibleFrom mproj mthis,
 			maybe (const True) inModule qname])
 		(newestPackage <$> findDeclaration db iname)
@@ -84,23 +83,23 @@
 		(qname, iname) = splitIdentifier ident
 
 -- | Whois symbol in scope
-whois :: Database -> Cabal -> FilePath -> String -> ExceptT String IO [Declaration]
-whois db cabal file ident = do
+whois :: Database -> FilePath -> String -> ExceptT String IO [Declaration]
+whois db file ident = do
 	(_, mthis, mproj) <- fileCtx db file
 	return $
 		newestPackage $ filter checkDecl $
-		view moduleDeclarations $ scopeModule $ resolveOne (fileDeps file cabal mproj db) $
+		view moduleDeclarations $ scopeModule $ resolveOne (fileDeps file mproj db) $
 		moduleLocals mthis
 	where
 		(qname, iname) = splitIdentifier ident
 		checkDecl d = fmap fromString qname `elem` scopes d && view declarationName d == fromString iname
 
 -- | Accessible modules
-scopeModules :: Database -> Cabal -> FilePath -> ExceptT String IO [Module]
-scopeModules db cabal file = do
+scopeModules :: Database -> FilePath -> ExceptT String IO [Module]
+scopeModules db file = do
 	(file', mthis, mproj) <- fileCtxMaybe db file
 	newestPackage <$> case mproj of
-		Nothing -> return $ maybe id (:) mthis $ selectModules (inCabal cabal . view moduleId) db
+		Nothing -> return $ maybe id (:) mthis $ selectModules (installed . view moduleId) db
 		Just proj -> let deps' = deps file' proj in
 			return $ concatMap (\p -> selectModules (p . view moduleId) db) [
 				inProject proj,
@@ -109,19 +108,19 @@
 		deps f p = delete (view projectName p) $ concatMap (view infoDepends) $ fileTargets p f
 
 -- | Symbols in scope
-scope :: Database -> Cabal -> FilePath -> Bool -> ExceptT String IO [Declaration]
-scope db cabal file False = do
+scope :: Database -> FilePath -> Bool -> ExceptT String IO [Declaration]
+scope db file False = do
 	(_, mthis, mproj) <- fileCtx db file
-	return $ view moduleDeclarations $ scopeModule $ resolveOne (fileDeps file cabal mproj db) mthis
-scope db cabal file True = concatMap (view moduleDeclarations) <$> scopeModules db cabal file
+	return $ view moduleDeclarations $ scopeModule $ resolveOne (fileDeps file mproj db) mthis
+scope db file True = concatMap (view moduleDeclarations) <$> scopeModules db file
 
 -- | Completions
-completions :: Database -> Cabal -> FilePath -> String -> Bool -> ExceptT String IO [Declaration]
-completions db cabal file prefix wide = do
+completions :: Database -> FilePath -> String -> Bool -> ExceptT String IO [Declaration]
+completions db file prefix wide = do
 	(_, mthis, mproj) <- fileCtx db file
 	return $
 		toListOf (each . minimalDecl) $ newestPackage $ filter checkDecl $
-		view moduleDeclarations $ scopeModule $ resolveOne (fileDeps file cabal mproj db) $
+		view moduleDeclarations $ scopeModule $ resolveOne (fileDeps file mproj db) $
 		dropImportLists mthis
 	where
 		(qname, iname) = splitIdentifier prefix
@@ -147,13 +146,17 @@
 checkDeclaration = (. view moduleDeclaration)
 
 -- | Allow only selected cabal sandbox
-restrictCabal :: Cabal -> ModuleId -> Bool
-restrictCabal cabal m = inCabal cabal m || not (byCabal m)
+restrictPackageDb :: PackageDb -> ModuleId -> Bool
+restrictPackageDb pdb m = inPackageDb pdb m || not (installed m)
 
+-- | Allow only selected cabal sandboxes
+restrictPackageDbStack :: PackageDbStack -> ModuleId -> Bool
+restrictPackageDbStack pdbs m = any (`inPackageDb` m) (packageDbs pdbs) || not (installed m)
+
 -- | Check whether module is visible from source file
 visibleFrom :: Maybe Project -> Module -> ModuleId -> Bool
 visibleFrom (Just p) this m = visible p (view moduleId this) m
-visibleFrom Nothing this m = view moduleId this == m || byCabal m
+visibleFrom Nothing this m = view moduleId this == m || installed m
 
 -- | Split identifier into module name and identifier itself
 splitIdentifier :: String -> (Maybe String, String)
@@ -183,10 +186,8 @@
 		return (file', Nothing, mproj')
 
 -- | Restrict only modules file depends on
-fileDeps :: FilePath -> Cabal -> Maybe Project -> Database -> Database
-fileDeps file cabal mproj = filterDB fileDeps' (const True) where
+fileDeps :: FilePath -> Maybe Project -> Database -> Database
+fileDeps file mproj = filterDB fileDeps' (const True) where
 	fileDeps' = liftM2 (||)
 		(maybe (const True) inProject mproj)
-		(liftM2 (&&)
-			(restrictCabal cabal)
-			(\m -> any (`inDepsOfTarget` m) (fromMaybe [] $ fileTargets <$> mproj <*> pure file)))
+		(\m -> any (`inDepsOfTarget` m) (fromMaybe [] $ fileTargets <$> mproj <*> pure file))
diff --git a/src/HsDev/Database.hs b/src/HsDev/Database.hs
--- a/src/HsDev/Database.hs
+++ b/src/HsDev/Database.hs
@@ -2,10 +2,10 @@
 
 module HsDev.Database (
 	Database(..),
-	databaseIntersection, nullDatabase, databaseLocals, allModules, allDeclarations, allPackages,
+	databaseIntersection, nullDatabase, databaseLocals, databasePackageDbs, allModules, allDeclarations, allPackages,
 	fromModule, fromProject,
 	filterDB,
-	projectDB, cabalDB, standaloneDB,
+	projectDB, packageDbDB, packageDbStackDB, standaloneDB,
 	selectModules, selectDeclarations, lookupModule, lookupInspected, lookupFile, refineProject,
 	getInspected,
 
@@ -17,7 +17,7 @@
 	Map
 	) where
 
-import Control.Lens (set, view, preview, _Just, each, (^..))
+import Control.Lens (set, view, preview, _Just, _Right, each, (^..))
 import Control.Monad (msum, join)
 import Control.DeepSeq (NFData(..))
 import Data.Aeson
@@ -84,6 +84,10 @@
 databaseLocals db = db {
 	databaseModules = fmap (fmap moduleLocals) (databaseModules db) }
 
+-- | All scanned sandboxes
+databasePackageDbs :: Database -> [PackageDb]
+databasePackageDbs db = ordNub $ databaseModules db ^.. each . inspectionResult . _Right . moduleLocation . modulePackageDb
+
 -- | All modules
 allModules :: Database -> [Module]
 allModules = rights . fmap (view inspectionResult) . databaseModules
@@ -118,10 +122,13 @@
 projectDB :: Project -> Database -> Database
 projectDB proj = filterDB (inProject proj) (((==) `on` view projectCabal) proj)
 
--- | Cabal database
-cabalDB :: Cabal -> Database -> Database
-cabalDB cabal = filterDB (inCabal cabal) (const False)
+-- | Package-db database
+packageDbDB :: PackageDb -> Database -> Database
+packageDbDB pdb = filterDB (inPackageDb pdb) (const False)
 
+packageDbStackDB :: PackageDbStack -> Database -> Database
+packageDbStackDB pdbs = filterDB (inPackageDbStack pdbs) (const False)
+
 -- | Standalone database
 standaloneDB :: Database -> Database
 standaloneDB = filterDB check' (const False) where
@@ -168,7 +175,7 @@
 
 -- | Structured database
 data Structured = Structured {
-	structuredCabals :: Map Cabal Database,
+	structuredPackageDbs :: Map PackageDb Database,
 	structuredProjects :: Map FilePath Database,
 	structuredFiles :: Database }
 		deriving (Eq, Ord)
@@ -178,11 +185,11 @@
 
 instance Group Structured where
 	add old new = Structured {
-		structuredCabals = structuredCabals new `M.union` structuredCabals old,
+		structuredPackageDbs = structuredPackageDbs new `M.union` structuredPackageDbs old,
 		structuredProjects = structuredProjects new `M.union` structuredProjects old,
 		structuredFiles = structuredFiles old `add` structuredFiles new }
 	sub old new = Structured {
-		structuredCabals = structuredCabals old `M.difference` structuredCabals new,
+		structuredPackageDbs = structuredPackageDbs old `M.difference` structuredPackageDbs new,
 		structuredProjects = structuredProjects old `M.difference` structuredProjects new,
 		structuredFiles = structuredFiles old `sub` structuredFiles new }
 	zero = Structured zero zero zero
@@ -210,14 +217,14 @@
 	mkMap key dbs = do
 		keys <- mapM key dbs
 		return $ M.fromList $ zip keys dbs
-	keyCabal :: Database -> Either String Cabal
+	keyCabal :: Database -> Either String PackageDb
 	keyCabal db = unique
 		"No cabal"
 		"Different module cabals"
-		(ordNub <$> mapM getCabal (allModules db))
+		(ordNub <$> mapM getPackageDb (allModules db))
 		where
-			getCabal m = case view moduleLocation m of
-				CabalModule c _ _ -> Right c
+			getPackageDb m = case view moduleLocation m of
+				InstalledModule c _ _ -> Right c
 				_ -> Left "Module have no cabal"
 	keyProj :: Database -> Either String FilePath
 	keyProj db = unique
@@ -233,14 +240,14 @@
 
 structurize :: Database -> Structured
 structurize db = Structured cs ps fs where
-	cs = M.fromList [(c, cabalDB c db) | c <- ordNub (mapMaybe modCabal (allModules db))]
-	ps = M.fromList [(pname, projectDB (project pname) db) | pname <- (databaseProjects db ^.. each . projectCabal)]
+	cs = M.fromList [(c, packageDbDB c db) | c <- ordNub (mapMaybe modPackageDb (allModules db))]
+	ps = M.fromList [(pname, projectDB (project pname) db) | pname <- databaseProjects db ^.. each . projectCabal]
 	fs = standaloneDB db
 
 merge :: Structured -> Database
 merge (Structured cs ps fs) = mconcat $ M.elems cs ++ M.elems ps ++ [fs]
 
-modCabal :: Module -> Maybe Cabal
-modCabal m = case view moduleLocation m of
-	CabalModule c _ _ -> Just c
+modPackageDb :: Module -> Maybe PackageDb
+modPackageDb m = case view moduleLocation m of
+	InstalledModule c _ _ -> Just c
 	_ -> Nothing
diff --git a/src/HsDev/Database/Update.hs b/src/HsDev/Database/Update.hs
--- a/src/HsDev/Database/Update.hs
+++ b/src/HsDev/Database/Update.hs
@@ -13,7 +13,7 @@
 	postStatus, waiter, updater, loadCache, getCache, runTask, runTasks,
 	readDB,
 
-	scanModule, scanModules, scanFile, scanFileContents, scanCabal, scanProjectFile, scanProject, scanDirectory,
+	scanModule, scanModules, scanFile, scanFileContents, scanCabal, prepareSandbox, scanSandbox, scanPackageDb, scanProjectFile, scanProjectStack, scanProject, scanDirectory, scanContents,
 	scanDocs, inferModTypes,
 	scan,
 	updateEvent, processEvent,
@@ -35,11 +35,14 @@
 import Control.Monad.Writer
 import Data.Aeson
 import Data.Aeson.Types
+import Data.List ((\\))
 import Data.Foldable (toList)
 import qualified Data.Map as M
-import Data.Maybe (mapMaybe, isJust, fromMaybe)
+import Data.Maybe (mapMaybe, isJust, fromMaybe, catMaybes)
+import Data.Maybe.JustIf
 import qualified Data.Text as T (unpack)
 import System.Directory (canonicalizePath, doesFileExist)
+import System.FilePath
 import qualified System.Log.Simple as Log
 
 import Control.Concurrent.Worker (inWorker)
@@ -49,6 +52,8 @@
 import HsDev.Display
 import HsDev.Inspect (inspectDocs, inspectDocsGhc)
 import HsDev.Project
+import HsDev.Sandbox
+import HsDev.Stack
 import HsDev.Symbols
 import HsDev.Tools.Ghc.Worker (ghcWorker)
 import HsDev.Tools.Ghc.Types (inferTypes)
@@ -78,12 +83,12 @@
 	wait db
 	dbval <- liftIO $ readAsync db
 	let
-		cabals = ordNub $ mapMaybe (preview moduleCabal) updatedMods
+		dbs = ordNub $ mapMaybe (preview modulePackageDb) updatedMods
 		projs = ordNub $ mapMaybe (preview $ moduleProject . _Just) updatedMods
 		stand = any moduleStandalone updatedMods
 
 		modifiedDb = mconcat $ concat [
-			map (`cabalDB` dbval) cabals,
+			map (`packageDbDB` dbval) dbs,
 			map (`projectDB` dbval) projs,
 			[standaloneDB dbval | stand]]
 	serverWriteCache modifiedDb
@@ -115,10 +120,10 @@
 			s <- getSession
 			im' <- liftExceptT $ S.scanModify (infer' s) im
 			updater $ return $ fromModule im'
-		infer' :: Session -> [String] -> Cabal -> Module -> ExceptT String IO Module
-		infer' s opts cabal m = case preview (moduleLocation . moduleFile) m of
+		infer' :: Session -> [String] -> PackageDbStack -> Module -> ExceptT String IO Module
+		infer' s opts pdbs m = case preview (moduleLocation . moduleFile) m of
 			Nothing -> return m
-			Just _ -> inWorkerT (sessionGhc s) $ inferTypes opts cabal m Nothing
+			Just _ -> inWorkerT (sessionGhc s) $ inferTypes opts pdbs m Nothing
 		inWorkerT w = ExceptT . inWorker w . runExceptT 
 
 -- | Post status
@@ -242,14 +247,51 @@
 	where
 		inFile f = maybe False (== f) . preview (moduleIdLocation . moduleFile)
 
--- | Scan cabal modules
-scanCabal :: UpdateMonad m => [String] -> Cabal -> m ()
-scanCabal opts cabalSandbox = runTask "scanning" cabalSandbox $ Log.scope "cabal" $ do
-	watch (\w -> watchSandbox w cabalSandbox opts)
-	mlocs <- liftExceptT $ listModules opts cabalSandbox
-	scan (Cache.loadCabal cabalSandbox) (cabalDB cabalSandbox) ((,,) <$> mlocs <*> pure [] <*> pure Nothing) opts $ \mlocs' -> do
-		ms <- liftExceptT $ browseModules opts cabalSandbox (mlocs' ^.. each . _1)
-		docs <- liftExceptT $ hdocsCabal cabalSandbox opts
+-- | Scan cabal modules, doesn't rescan if already scanned
+scanCabal :: UpdateMonad m => [String] -> m ()
+scanCabal opts = Log.scope "cabal" $ do
+	dbval <- readDB
+	let
+		scannedDbs = databasePackageDbs dbval
+		unscannedDbs = filter ((`notElem` scannedDbs) . topPackageDb) $ reverse $ packageDbStacks userDb
+	if null unscannedDbs
+		then do
+			Log.log Log.Trace $ "cabal (global-db and user-db) already scanned"
+		else runTasks $ map (scanPackageDb opts) unscannedDbs
+
+-- | Prepare sandbox for scanning. This is used for stack project to build & configure.
+prepareSandbox :: UpdateMonad m => Sandbox -> m ()
+prepareSandbox sbox@(Sandbox StackWork fpath) = Log.scope "prepare" $ runTasks [
+	runTask "building dependencies" sbox $ void $ liftIO $ runMaybeT $ buildDeps myaml,
+	runTask "configuring" sbox $ void $ liftIO $ runMaybeT $ configure myaml]
+	where
+		myaml = Just $ takeDirectory fpath </> "stack.yaml"
+prepareSandbox _ = return ()
+
+-- | Scan sandbox modules, doesn't rescan if already scanned
+scanSandbox :: UpdateMonad m => [String] -> Sandbox -> m ()
+scanSandbox opts sbox = Log.scope "sandbox" $ do
+	dbval <- readDB
+	prepareSandbox sbox
+	pdbs <- liftExceptT $ sandboxPackageDbStack sbox
+	let
+		scannedDbs = databasePackageDbs dbval
+		unscannedDbs = filter ((`notElem` scannedDbs) . topPackageDb) $ reverse $ packageDbStacks pdbs
+	if null unscannedDbs
+		then do
+			Log.log Log.Trace $ "sandbox already scanned"
+		else runTasks $ map (scanPackageDb opts) unscannedDbs
+
+-- | Scan top of package-db stack, usable for rescan
+scanPackageDb :: UpdateMonad m => [String] -> PackageDbStack -> m ()
+scanPackageDb opts pdbs = runTask "scanning" (topPackageDb pdbs) $ Log.scope "package-db" $ do
+	watch (\w -> watchPackageDb w pdbs opts)
+	mlocs <- liftM
+		(filter (\mloc -> preview modulePackageDb mloc == Just (topPackageDb pdbs))) $
+		liftExceptT $ listModules opts pdbs
+	scan (Cache.loadPackageDb (topPackageDb pdbs)) (packageDbDB (topPackageDb pdbs)) ((,,) <$> mlocs <*> pure [] <*> pure Nothing) opts $ \mlocs' -> do
+		ms <- liftExceptT $ browseModules opts pdbs (mlocs' ^.. each . _1)
+		docs <- liftExceptT $ hdocsCabal pdbs opts
 		updater $ return $ mconcat $ map (fromModule . fmap (setDocs' docs)) ms
 	where
 		setDocs' :: Map String (Map String String) -> Module -> Module
@@ -259,12 +301,20 @@
 scanProjectFile :: UpdateMonad m => [String] -> FilePath -> m Project
 scanProjectFile opts cabal = runTask "scanning" cabal $ liftExceptT $ S.scanProjectFile opts cabal
 
+-- | Scan project and related package-db stack
+scanProjectStack :: UpdateMonad m => [String] -> FilePath -> m ()
+scanProjectStack opts cabal = do
+	proj <- scanProjectFile opts cabal
+	scanProject opts cabal
+	sbox <- liftIO $ searchSandbox (view projectPath proj)
+	maybe (scanCabal opts) (scanSandbox opts) sbox
+
 -- | Scan project
 scanProject :: UpdateMonad m => [String] -> FilePath -> m ()
 scanProject opts cabal = runTask "scanning" (project cabal) $ Log.scope "project" $ do
 	proj <- scanProjectFile opts cabal
 	watch (\w -> watchProject w proj opts)
-	(_, sources) <- liftExceptT $ S.enumProject proj
+	S.ScanContents _ [(_, sources)] _ <- liftExceptT $ S.enumProject proj
 	scan (Cache.loadProject $ view projectCabal proj) (projectDB proj) sources opts $ \ms -> do
 		scanModules opts ms
 		updater $ return $ fromProject proj
@@ -272,14 +322,32 @@
 -- | Scan directory for source files and projects
 scanDirectory :: UpdateMonad m => [String] -> FilePath -> m ()
 scanDirectory opts dir = runTask "scanning" dir $ Log.scope "directory" $ do
-	S.ScanContents standSrcs projSrcs sboxes <- liftExceptT $ S.enumDirectory dir
+	S.ScanContents standSrcs projSrcs pdbss <- liftExceptT $ S.enumDirectory dir
 	runTasks [scanProject opts (view projectCabal p) | (p, _) <- projSrcs]
-	runTasks $ map (scanCabal opts) sboxes
+	runTasks $ map (scanPackageDb opts) pdbss -- TODO: Don't rescan
 	mapMOf_ (each . _1) (watch . flip watchModule) standSrcs
 	scan (Cache.loadFiles (dir `isParent`)) (filterDB inDir (const False) . standaloneDB) standSrcs opts $ scanModules opts
 	where
 		inDir = maybe False (dir `isParent`) . preview (moduleIdLocation . moduleFile)
 
+scanContents :: UpdateMonad m => [String] -> S.ScanContents -> m ()
+scanContents opts (S.ScanContents standSrcs projSrcs pdbss) = do
+	dbval <- readDB
+	let
+		projs = databaseProjects dbval ^.. each . projectCabal
+		pdbs = databasePackageDbs dbval
+		files = allModules (standaloneDB dbval) ^.. each . moduleLocation . moduleFile
+		srcs = standSrcs ^.. each . _1 . moduleFile
+		inSrcs src = src `elem` srcs && src `notElem` files
+		inFiles = maybe False inSrcs . preview (moduleIdLocation . moduleFile)
+	mapMOf_ (each . _1 . projectCabal) (\p -> Log.log Log.Trace ("scanning project: {}" ~~ p)) projSrcs
+	runTasks [scanProject opts (view projectCabal p) | (p, _) <- projSrcs, view projectCabal p `notElem` projs]
+	mapMOf_ (each . _1 . moduleFile) (\f -> Log.log Log.Trace ("scanning file: {}" ~~ f)) standSrcs
+	mapMOf_ (each . _1) (watch . flip watchModule) standSrcs
+	scan (Cache.loadFiles inSrcs) (filterDB inFiles (const False) . standaloneDB) standSrcs opts $ scanModules opts
+	mapMOf_ each (\s -> Log.log Log.Trace ("scanning package-db: {}" ~~ topPackageDb s)) pdbss
+	runTasks [scanPackageDb opts pdbs' | pdbs' <- pdbss, topPackageDb pdbs' `notElem` pdbs]
+
 -- | Scan docs for inspected modules
 scanDocs :: UpdateMonad m => [InspectedModule] -> m ()
 scanDocs ims = do
@@ -341,11 +409,11 @@
 			~~ ("proj" %= view projectName proj)
 		scanProject projOpts $ view projectCabal proj
 	| otherwise = return ()
-updateEvent (WatchedSandbox cabal cabalOpts) e
+updateEvent (WatchedPackageDb pdbs opts) e
 	| isConf e = do
-		Log.log Log.Info $ "Sandbox {cabal} changed"
-			~~ ("cabal" %= cabal)
-		scanCabal cabalOpts cabal
+		Log.log Log.Info $ "Package db {package} changed"
+			~~ ("package" %= topPackageDb pdbs)
+		scanPackageDb opts pdbs
 	| otherwise = return ()
 updateEvent WatchedModule e
 	| isSource e = do
diff --git a/src/HsDev/Display.hs b/src/HsDev/Display.hs
--- a/src/HsDev/Display.hs
+++ b/src/HsDev/Display.hs
@@ -10,22 +10,24 @@
 
 import Text.Format
 
-import HsDev.Cabal
-import HsDev.Symbols.Location
+import HsDev.PackageDb
 import HsDev.Project
+import HsDev.Sandbox
+import HsDev.Symbols.Location
 
 class Display a where
 	display :: a -> String
 	displayType :: a -> String
 
-instance Display Cabal where
-	display Cabal = "cabal"
-	display (Sandbox p) = "sandbox " ++ p
-	displayType _ = "cabal"
+instance Display PackageDb where
+	display GlobalDb = "global-db"
+	display UserDb = "user-db"
+	display (PackageDb p) = "package-db " ++ p
+	displayType _ = "package-db"
 
 instance Display ModuleLocation where
 	display (FileModule f _) = f
-	display (CabalModule _ _ n) = n
+	display (InstalledModule _ _ n) = n
 	display (ModuleSource s) = fromMaybe "" s
 	displayType _ = "module"
 
@@ -33,11 +35,16 @@
 	display = view projectName
 	displayType _ = "project"
 
+instance Display Sandbox where
+	display (Sandbox _ fpath) = fpath
+	displayType (Sandbox CabalSandbox _) = "cabal-sandbox"
+	displayType (Sandbox StackWork _) = "stack-work"
+
 instance Display FilePath where
 	display = id
 	displayType _ = "path"
 
-instance FormatBuild Cabal where
+instance FormatBuild PackageDb where
 	formatBuild = formatBuild . display
 
 instance FormatBuild ModuleLocation where
@@ -45,3 +52,4 @@
 
 instance FormatBuild Project where
 	formatBuild = formatBuild . display
+
diff --git a/src/HsDev/PackageDb.hs b/src/HsDev/PackageDb.hs
new file mode 100644
--- /dev/null
+++ b/src/HsDev/PackageDb.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}
+
+module HsDev.PackageDb (
+	PackageDb(..), packageDb,
+	PackageDbStack(..), packageDbStack, globalDb, userDb, fromPackageDb, fromPackageDbs,
+	topPackageDb, packageDbs, packageDbStacks,
+	isSubStack,
+
+	packageDbOpt, packageDbStackOpts
+	) where
+
+import Control.Applicative
+import Control.Monad (guard)
+import Control.Lens (makeLenses, each)
+import Control.DeepSeq (NFData(..))
+import Data.Aeson
+import Data.List (tails, isSuffixOf)
+
+import System.Directory.Paths
+import HsDev.Util ((.::))
+
+data PackageDb = GlobalDb | UserDb | PackageDb { _packageDb :: FilePath } deriving (Eq, Ord, Read, Show)
+
+makeLenses ''PackageDb
+
+instance NFData PackageDb where
+	rnf GlobalDb = ()
+	rnf UserDb = ()
+	rnf (PackageDb p) = rnf p
+
+instance ToJSON PackageDb where
+	toJSON GlobalDb = "global-db"
+	toJSON UserDb = "user-db"
+	toJSON (PackageDb p) = object ["package-db" .= p]
+
+instance FromJSON PackageDb where
+	parseJSON v = globalP v <|> userP v <|> dbP v where
+		globalP = withText "global-db" (\s -> guard (s == "global-db") >> return GlobalDb)
+		userP = withText "user-db" (\s -> guard (s == "user-db") >> return UserDb)
+		dbP = withObject "package-db" pathP where
+			pathP obj = PackageDb <$> obj .:: "package-db"
+
+instance Paths PackageDb where
+	paths _ GlobalDb = pure GlobalDb
+	paths _ UserDb = pure UserDb
+	paths f (PackageDb p) = PackageDb <$> f p
+
+-- | Stack of PackageDb in reverse order
+newtype PackageDbStack = PackageDbStack { _packageDbStack :: [PackageDb] } deriving (Eq, Ord, Read, Show)
+
+makeLenses ''PackageDbStack
+
+instance NFData PackageDbStack where
+	rnf (PackageDbStack ps) = rnf ps
+
+instance ToJSON PackageDbStack where
+	toJSON (PackageDbStack ps) = toJSON ps
+
+instance FromJSON PackageDbStack where
+	parseJSON = fmap PackageDbStack . parseJSON
+
+instance Paths PackageDbStack where
+	paths f (PackageDbStack ps) = PackageDbStack <$> (each . paths) f ps
+
+-- | Global db stack
+globalDb :: PackageDbStack
+globalDb = PackageDbStack []
+
+-- | User db stack
+userDb :: PackageDbStack
+userDb = PackageDbStack [UserDb]
+
+-- | Make package-db from one package-db
+fromPackageDb :: FilePath -> PackageDbStack
+fromPackageDb = PackageDbStack . return . PackageDb
+
+-- | Make package-db stack from paths
+fromPackageDbs :: [FilePath] -> PackageDbStack
+fromPackageDbs = PackageDbStack . map PackageDb . reverse
+
+-- | Get top package-db for package-db stack
+topPackageDb :: PackageDbStack -> PackageDb
+topPackageDb (PackageDbStack []) = GlobalDb
+topPackageDb (PackageDbStack (d:_)) = d
+
+-- | Get list of package-db in stack, adds additional global-db at bottom
+packageDbs :: PackageDbStack -> [PackageDb]
+packageDbs = (GlobalDb :) . reverse . _packageDbStack
+
+-- | Get stacks for each package-db in stack
+packageDbStacks :: PackageDbStack -> [PackageDbStack]
+packageDbStacks = map PackageDbStack . tails . _packageDbStack
+
+-- | Is one package-db stack substack of another
+isSubStack :: PackageDbStack -> PackageDbStack -> Bool
+isSubStack (PackageDbStack l) (PackageDbStack r) = l `isSuffixOf` r
+
+-- | Get ghc options for package-db
+packageDbOpt :: PackageDb -> String
+packageDbOpt GlobalDb = "-global-package-db"
+packageDbOpt UserDb = "-user-package-db"
+packageDbOpt (PackageDb p) = "-package-db " ++ p
+
+-- | Get ghc options for package-db stack
+packageDbStackOpts :: PackageDbStack -> [String]
+packageDbStackOpts (PackageDbStack ps) = "-no-user-package-db" : map packageDbOpt (reverse ps)
diff --git a/src/HsDev/Project.hs b/src/HsDev/Project.hs
--- a/src/HsDev/Project.hs
+++ b/src/HsDev/Project.hs
@@ -3,17 +3,18 @@
 module HsDev.Project (
 	Project(..),
 	ProjectDescription(..), Target(..), Library(..), Executable(..), Test(..), Info(..), infoSourceDirsDef,
-	readProject, loadProject, getProjectSandbox,
+	readProject, loadProject,
 	project,
 	Extensions(..), withExtensions,
 	infos, inTarget, fileTargets, findSourceDir, sourceDirs,
 
-	projectName, projectPath, projectCabal, projectDescription, projectLibrary, projectExecutables, projectTests,
+	projectName, projectPath, projectCabal, projectDescription, projectVersion, projectLibrary, projectExecutables, projectTests,
 	libraryModules, libraryBuildInfo,
 	executableName, executablePath, executableBuildInfo,
 	testName, testEnabled, testBuildInfo,
 	infoDepends, infoLanguage, infoExtensions, infoGHCOptions, infoSourceDirs,
 	extensions, ghcOptions, entity,
+	targetOpts,
 
 	-- * Helpers
 	showExtension, flagExtension, extensionFlag,
@@ -22,14 +23,16 @@
 
 import Control.Arrow
 import Control.DeepSeq (NFData(..))
-import Control.Lens (makeLenses, Simple, Lens, view, lens)
+import Control.Lens (makeLenses, Simple, Lens, view, lens, at)
 import Control.Exception
 import Control.Monad.Except
 import Data.Aeson
 import Data.Aeson.Types (Parser)
 import Data.List
 import Data.Maybe
+import Data.Monoid
 import Data.Ord
+import Data.Version (showVersion)
 import Distribution.Compiler (CompilerFlavor(GHC))
 import qualified Distribution.Package as P
 import qualified Distribution.PackageDescription as PD
@@ -40,7 +43,6 @@
 import Language.Haskell.Extension
 import System.FilePath
 
-import HsDev.Cabal (Cabal, getSandbox)
 import HsDev.Util
 
 -- | Cabal project
@@ -81,6 +83,7 @@
 		v .:: "description"
 
 data ProjectDescription = ProjectDescription {
+	_projectVersion :: String,
 	_projectLibrary :: Maybe Library,
 	_projectExecutables :: [Executable],
 	_projectTests :: [Test] }
@@ -94,12 +97,14 @@
 
 instance ToJSON ProjectDescription where
 	toJSON d = object [
+		"version" .= _projectVersion d,
 		"library" .= _projectLibrary d,
 		"executables" .= _projectExecutables d,
 		"tests" .= _projectTests d]
 
 instance FromJSON ProjectDescription where
 	parseJSON = withObject "project description" $ \v -> ProjectDescription <$>
+		v .:: "version" <*>
 		v .:: "library" <*>
 		v .:: "executables" <*>
 		v .:: "tests"
@@ -195,6 +200,15 @@
 	_infoSourceDirs :: [FilePath] }
 		deriving (Eq, Read)
 
+instance Monoid Info where
+	mempty = Info [] Nothing [] [] []
+	mappend l r = Info
+		(ordNub $ _infoDepends l ++ _infoDepends r)
+		(getFirst $ First (_infoLanguage l) `mappend` First (_infoLanguage r))
+		(_infoExtensions l ++ _infoExtensions r)
+		(_infoGHCOptions l ++ _infoGHCOptions r)
+		(ordNub $ _infoSourceDirs l ++ _infoSourceDirs r)
+
 -- | infoSourceDirs lens with default
 infoSourceDirsDef :: Simple Lens Info [FilePath]
 infoSourceDirsDef = lens get' set' where
@@ -235,6 +249,7 @@
 analyzeCabal :: String -> Either String ProjectDescription
 analyzeCabal source = case liftM flattenDescr $ parsePackageDescription source of
 	ParseOk _ r -> Right ProjectDescription {
+		_projectVersion = showVersion $ P.pkgVersion $ PD.package r,
 		_projectLibrary = fmap toLibrary $ PD.library r,
 		_projectExecutables = fmap toExecutable $ PD.executables r,
 		_projectTests = fmap toTest $ PD.testSuites r }
@@ -265,7 +280,7 @@
 				(\(n, t) -> t { PD.testName = n }) }
 			where
 				insertInfo :: (a -> PD.BuildInfo) -> (PD.BuildInfo -> a -> a) -> [P.Dependency] -> a -> a
-				insertInfo f s deps x = s ((f x) { PD.targetBuildDepends = deps }) x
+				insertInfo f s deps' x = s ((f x) { PD.targetBuildDepends = deps' }) x
 
 		flattenTree :: Monoid a => (c -> a -> a) -> PD.CondTree v c a -> a
 		flattenTree f (PD.CondNode x cs cmps) = f cs x `mappend` mconcat (concatMap flattenBranch cmps) where
@@ -286,23 +301,18 @@
 	| isJust (_projectDescription p) = return p
 	| otherwise = readProject (_projectCabal p)
 
--- | Find project sandbox
-getProjectSandbox :: Project -> IO Cabal
-getProjectSandbox = getSandbox . _projectPath
-
 -- | Make project by .cabal file
 project :: FilePath -> Project
-project file
-	| takeExtension file == ".cabal" = Project {
-		_projectName = takeBaseName (takeDirectory file),
-		_projectPath = takeDirectory file,
-		_projectCabal = file,
-		_projectDescription = Nothing }
-	| otherwise = Project {
-		_projectName = takeBaseName file,
-		_projectPath = file,
-		_projectCabal = file </> (takeBaseName file <.> "cabal"),
-		_projectDescription = Nothing }
+project file = Project {
+	_projectName = takeBaseName (takeDirectory cabal),
+	_projectPath = takeDirectory cabal,
+	_projectCabal = cabal,
+	_projectDescription = Nothing }
+	where
+		file' = dropTrailingPathSeparator $ normalise file
+		cabal
+			| takeExtension file' == ".cabal" = file'
+			| otherwise = file' </> (takeBaseName file' <.> "cabal")
 
 -- | Entity with project extensions
 data Extensions a = Extensions {
@@ -369,6 +379,13 @@
 parseDT :: Distribution.Text.Text a => String -> String -> Parser a
 parseDT typeName v = maybe err return (simpleParse v) where
 	err = fail $ "Can't parse " ++ typeName ++ ": " ++ v
+
+-- | Get options for specific target
+targetOpts :: Info -> [String]
+targetOpts info' = concat [
+	["-i" ++ s | s <- _infoSourceDirs info'],
+	extensionsOpts $ withExtensions () info',
+	["-package " ++ p | p <- _infoDepends info']]
 
 -- | Extension as flag name
 showExtension :: Extension -> String
diff --git a/src/HsDev/Sandbox.hs b/src/HsDev/Sandbox.hs
new file mode 100644
--- /dev/null
+++ b/src/HsDev/Sandbox.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
+
+module HsDev.Sandbox (
+	SandboxType(..), Sandbox(..), sandboxType, sandbox,
+	isSandbox, guessSandboxType, sandboxFromPath,
+	findSandbox, searchSandbox, sandboxPackageDbStack, searchPackageDbStack, restorePackageDbStack,
+
+	-- * cabal-sandbox util
+	cabalSandboxLib, cabalSandboxPackageDb
+	-- * stack-work util
+	) where
+
+import Control.Arrow
+import Control.Applicative
+import Control.DeepSeq (NFData(..))
+import Control.Monad.Trans.Maybe
+import Control.Monad.Except
+import Control.Lens (view, makeLenses, Lens', lens)
+import Data.Aeson
+import Data.Maybe (isJust, fromMaybe)
+import Data.List ((\\))
+import qualified Data.Text as T (unpack)
+import Distribution.Compiler
+import Distribution.System
+import qualified Distribution.Text as T (display)
+import System.FilePath
+import System.Directory
+
+import System.Directory.Paths
+import HsDev.PackageDb
+import HsDev.Scan.Browse (withPackages)
+import HsDev.Stack
+import HsDev.Util (searchPath)
+
+import qualified GHC
+import qualified Packages as GHC
+
+data SandboxType = CabalSandbox | StackWork deriving (Eq, Ord, Read, Show, Enum, Bounded)
+
+data Sandbox = Sandbox { _sandboxType :: SandboxType, _sandbox :: FilePath } deriving (Eq, Ord)
+
+makeLenses ''Sandbox
+
+instance NFData SandboxType where
+	rnf CabalSandbox = ()
+	rnf StackWork = ()
+
+instance NFData Sandbox where
+	rnf (Sandbox t p) = rnf t `seq` rnf p
+
+instance Show Sandbox where
+	show (Sandbox _ p) = p
+
+instance ToJSON Sandbox where
+	toJSON (Sandbox _ p) = toJSON p
+
+instance FromJSON Sandbox where
+	parseJSON = withText "sandbox" sandboxPath where
+		sandboxPath = maybe (fail "Not a sandbox") return . sandboxFromPath . T.unpack
+
+instance Paths Sandbox where
+	paths f (Sandbox st p) = Sandbox st <$> f p
+
+isSandbox :: FilePath -> Bool
+isSandbox = isJust . guessSandboxType
+
+guessSandboxType :: FilePath -> Maybe SandboxType
+guessSandboxType fpath
+	| takeFileName fpath == ".cabal-sandbox" = Just CabalSandbox
+	| takeFileName fpath == ".stack-work" = Just StackWork
+	| otherwise = Nothing
+
+sandboxFromPath :: FilePath -> Maybe Sandbox
+sandboxFromPath fpath = Sandbox <$> guessSandboxType fpath <*> pure fpath
+
+-- | Find sandbox in path
+findSandbox :: FilePath -> IO (Maybe Sandbox)
+findSandbox fpath = do
+	fpath' <- canonicalize fpath
+	isDir <- doesDirectoryExist fpath'
+	if isDir
+		then do
+			dirs <- liftM ((fpath' :) . map (fpath' </>) . (\\ [".", ".."])) $ getDirectoryContents fpath'
+			return $ msum $ map sandboxFromDir dirs
+		else return Nothing
+	where
+		sandboxFromDir :: FilePath -> Maybe Sandbox
+		sandboxFromDir fpath
+			| takeFileName fpath == "stack.yaml" = sandboxFromPath (takeDirectory fpath </> ".stack-work")
+			| otherwise = sandboxFromPath fpath
+
+-- | Search sandbox by parent directory
+searchSandbox :: FilePath -> IO (Maybe Sandbox)
+searchSandbox p = runMaybeT $ searchPath p (MaybeT . findSandbox)
+
+-- | Get package-db stack for sandbox
+sandboxPackageDbStack :: Sandbox -> ExceptT String IO PackageDbStack
+sandboxPackageDbStack (Sandbox CabalSandbox fpath) = do
+	dir <- cabalSandboxPackageDb
+	return $ PackageDbStack [PackageDb $ fpath </> dir]
+sandboxPackageDbStack (Sandbox StackWork fpath) = maybeToExceptT "Can't locate stack environment" $
+	liftM (view stackPackageDbStack) $ projectEnv $ takeDirectory fpath
+
+-- | Search package-db stack with user-db as default
+searchPackageDbStack :: FilePath -> IO PackageDbStack
+searchPackageDbStack p = do
+	mbox <- searchSandbox p
+	case mbox of
+		Nothing -> return userDb
+		Just sbox -> liftM (either (const userDb) id) $ runExceptT $ sandboxPackageDbStack sbox
+	where
+		userDb = PackageDbStack [UserDb]
+
+-- | Restore package-db stack by package-db
+restorePackageDbStack :: PackageDb -> IO PackageDbStack
+restorePackageDbStack GlobalDb = return globalDb
+restorePackageDbStack UserDb = return userDb
+restorePackageDbStack (PackageDb p) = liftM (fromMaybe $ fromPackageDb p) $ runMaybeT $ do
+	sbox <- MaybeT $ searchSandbox p
+	exceptToMaybeT $ sandboxPackageDbStack sbox
+
+-- | Get actual sandbox build path: <arch>-<platform>-<compiler>-<version>
+cabalSandboxLib :: ExceptT String IO FilePath
+cabalSandboxLib = do
+	res <- withPackages ["-no-user-package-db"] $
+		return .
+		map (GHC.packageNameString &&& GHC.packageVersion) .
+		fromMaybe [] .
+		GHC.pkgDatabase
+	let
+		compiler = T.display buildCompilerFlavor
+		CompilerId _ version = buildCompilerId
+		ver = maybe (T.display version) T.display $ lookup compiler res
+	return $ T.display buildPlatform ++ "-" ++ compiler ++ "-" ++ ver
+
+-- | Get sandbox package-db: <arch>-<platform>-<compiler>-<version>-packages.conf.d
+cabalSandboxPackageDb :: ExceptT String IO FilePath
+cabalSandboxPackageDb = liftM (++ "-packages.conf.d") cabalSandboxLib
diff --git a/src/HsDev/Scan.hs b/src/HsDev/Scan.hs
--- a/src/HsDev/Scan.hs
+++ b/src/HsDev/Scan.hs
@@ -1,7 +1,10 @@
+{-# LANGUAGE FlexibleInstances #-}
+
 module HsDev.Scan (
 	-- * Enumerate functions
-	enumCabal, CompileFlag, ModuleToScan, ProjectToScan, SandboxToScan, ScanContents(..),
-	enumProject, enumDirectory,
+	CompileFlag, ModuleToScan, ProjectToScan, PackageDbToScan, ScanContents(..),
+	EnumContents(..),
+	enumProject, enumSandbox, enumDirectory,
 
 	-- * Scan
 	scanProjectFile,
@@ -15,47 +18,103 @@
 
 import Control.Applicative ((<|>))
 import Control.DeepSeq
-import Control.Lens (view, preview, set, _Right, _1, _2, _3, (^.))
+import Control.Lens (view, preview, set, over, each, _Right, _1, _2, _3, (^.), (^..), at)
 import Control.Monad.Except
 import Data.Maybe (catMaybes, fromMaybe, isJust)
+import Data.List (intercalate)
 import System.Directory
+import Text.Format
 
+import Data.Deps
 import HsDev.Scan.Browse (browsePackages)
+import HsDev.Server.Types (FileContents(..))
+import HsDev.Sandbox
 import HsDev.Symbols
 import HsDev.Symbols.Types
 import HsDev.Database
+import HsDev.Display
 import HsDev.Tools.GhcMod
 import HsDev.Inspect
 import HsDev.Util
 
--- | Enum cabal modules
-enumCabal :: [String] -> Cabal -> ExceptT String IO [ModuleLocation]
-enumCabal = list
-
 -- | Compile flags
 type CompileFlag = String
 -- | Module with flags ready to scan
 type ModuleToScan = (ModuleLocation, [CompileFlag], Maybe String)
 -- | Project ready to scan
 type ProjectToScan = (Project, [ModuleToScan])
--- | Cabal sandbox to scan
-type SandboxToScan = Cabal
+-- | Package-db sandbox to scan (top of stack)
+type PackageDbToScan = PackageDbStack
 
 -- | Scan info
 data ScanContents = ScanContents {
 	modulesToScan :: [ModuleToScan],
 	projectsToScan :: [ProjectToScan],
-	sandboxesToScan :: [SandboxToScan] }
+	sandboxesToScan :: [PackageDbStack] }
 
 instance NFData ScanContents where
 	rnf (ScanContents ms ps ss) = rnf ms `seq` rnf ps `seq` rnf ss
 
+instance Monoid ScanContents where
+	mempty = ScanContents [] [] []
+	mappend (ScanContents lm lp ls) (ScanContents rm rp rs) = ScanContents
+		(uniqueBy (view _1) $ lm ++ rm)
+		(uniqueBy (view _1) $ lp ++ rp)
+		(ordNub $ ls ++ rs)
+
+instance FormatBuild ScanContents where
+	formatBuild (ScanContents ms ps cs) = formatBuild str where
+		str :: String
+		str = format "modules: {}, projects: {}, package-dbs: {}"
+			~~ (intercalate ", " $ ms ^.. each . _1 . moduleFile)
+			~~ (intercalate ", " $ ps ^.. each . _1 . projectPath)
+			~~ (intercalate ", " $ map (display . topPackageDb) $ cs ^.. each)
+
+class EnumContents a where
+	enumContents :: a -> ExceptT String IO ScanContents
+
+instance EnumContents ModuleLocation where
+	enumContents mloc = return $ ScanContents [(mloc, [], Nothing)] [] []
+
+instance EnumContents (Extensions ModuleLocation) where
+	enumContents ex = return $ ScanContents [(view entity ex, extensionsOpts ex, Nothing)] [] []
+
+instance EnumContents Project where
+	enumContents = enumProject
+
+instance EnumContents PackageDbStack where
+	enumContents pdbs = return $ ScanContents [] [] (packageDbStacks pdbs)
+
+instance EnumContents Sandbox where
+	enumContents = enumSandbox
+
+instance {-# OVERLAPPING #-} EnumContents a => EnumContents [a] where
+	enumContents = liftM mconcat . tries . map enumContents
+
+instance {-# OVERLAPS #-} EnumContents FilePath where
+	enumContents f
+		| haskellSource f = do
+			mproj <- liftEIO $ locateProject f
+			case mproj of
+				Nothing -> enumContents $ FileModule f Nothing
+				Just proj -> do
+					ScanContents _ [(_, mods)] _ <- enumContents proj
+					return $ ScanContents (filter ((== Just f) . preview (_1 . moduleFile)) mods) [] []
+		| otherwise = enumDirectory f
+
+instance EnumContents FileContents where
+	enumContents (FileContents f cts)
+		| haskellSource f = do
+			ScanContents [(m, opts, _)] _ _ <- enumContents f
+			return $ ScanContents [(m, opts, Just cts)] [] []
+		| otherwise = return mempty
+
 -- | Enum project sources
-enumProject :: Project -> ExceptT String IO ProjectToScan
+enumProject :: Project -> ExceptT String IO ScanContents
 enumProject p = do
 	p' <- loadProject p
-	cabal <- liftE $ searchSandbox (view projectPath p')
-	pkgs <- liftM (map $ view packageName) $ browsePackages [] cabal
+	pdbs <- liftE $ searchPackageDbStack (view projectPath p')
+	pkgs <- liftM (map $ view packageName) $ browsePackages [] pdbs
 	let
 		projOpts :: FilePath -> [String]
 		projOpts f = concatMap makeOpts $ fileTargets p' f where
@@ -65,8 +124,15 @@
 				["-package " ++ view projectName p'],
 				["-package " ++ dep | dep <- view infoDepends i, dep `elem` pkgs]]
 	srcs <- projectSources p'
-	return (p', [(FileModule (view entity src) (Just p'), extensionsOpts src ++ projOpts (view entity src), Nothing) | src <- srcs])
+	let
+		mlocs = over each (\src -> over ghcOptions (++ projOpts (view entity src)) . over entity (\f -> FileModule f (Just p')) $ src) srcs
+	mods <- liftM modulesToScan $ enumContents mlocs
+	return $ ScanContents [] [(p', mods)] [] -- (sandboxCabals sboxes)
 
+-- | Enum sandbox
+enumSandbox :: Sandbox -> ExceptT String IO ScanContents
+enumSandbox = sandboxPackageDbStack >=> enumContents
+
 -- | Enum directory modules
 enumDirectory :: FilePath -> ExceptT String IO ScanContents
 enumDirectory dir = do
@@ -75,15 +141,16 @@
 		projects = filter cabalFile cts
 		sources = filter haskellSource cts
 	dirs <- liftE $ filterM doesDirectoryExist cts
-	sboxes <- liftM catMaybes $ triesMap (liftE . findPackageDb) dirs
-	projs <- triesMap (enumProject . project) projects
+	sboxes <- liftM catMaybes $ triesMap (liftE . findSandbox) dirs
+	pdbs <- mapM enumSandbox sboxes
+	projs <- liftM mconcat $ triesMap (enumProject . project) projects
 	let
-		projPaths = map (view projectPath . fst) projs
+		projPaths = map (view projectPath . fst) $ projectsToScan projs
 		standalone = map (`FileModule` Nothing) $ filter (\s -> not (any (`isParent` s) projPaths)) sources
-	return ScanContents {
-		modulesToScan = [(s, [], Nothing) | s <- standalone],
-		projectsToScan = projs,
-		sandboxesToScan = map Sandbox sboxes }
+	return $ mconcat [
+		ScanContents [(s, [], Nothing) | s <- standalone] [] [],
+		projs,
+		mconcat pdbs]
 
 -- | Scan project file
 scanProjectFile :: [String] -> FilePath -> ExceptT String IO Project
@@ -101,20 +168,30 @@
 -- 	infer' m = tryInfer <|> return m where
 -- 		tryInfer = mapExceptT (withCurrentDirectory (sourceModuleRoot (moduleName m) f)) $
 -- 			runGhcMod defaultOptions $ inferTypes opts Cabal m
-scanModule _ opts (CabalModule c p n) _ = browse opts c n p
+scanModule _ opts (InstalledModule c p n) _ = do
+	pdbs <- liftIO $ getDbs c
+	browse opts pdbs n p
+	where
+		getDbs :: PackageDb -> IO PackageDbStack
+		getDbs = maybe (return userDb) searchPackageDbStack . preview packageDb
 scanModule _ _ (ModuleSource _) _ = throwError "Can inspect only modules in file or cabal"
 
 -- | Scan additional info and modify scanned module. Dones't fail on error, just left module unchanged
-scanModify :: ([String] -> Cabal -> Module -> ExceptT String IO Module) -> InspectedModule -> ExceptT String IO InspectedModule
+scanModify :: ([String] -> PackageDbStack -> Module -> ExceptT String IO Module) -> InspectedModule -> ExceptT String IO InspectedModule
 scanModify f im = traverse f' im <|> return im where
-	-- TODO: Get actual sandbox
-	f' = f (fromMaybe [] $ preview (inspection . inspectionOpts) im) Cabal
+	f' m = do
+		pdbs <- liftIO $ case view moduleLocation m of
+			-- TODO: Get actual sandbox stack
+			FileModule fpath _ -> searchPackageDbStack fpath
+			InstalledModule pdb _ _ -> maybe (return userDb) searchPackageDbStack $ preview packageDb pdb
+			_ -> return userDb
+		f (fromMaybe [] $ preview (inspection . inspectionOpts) im) pdbs m
 
 -- | Is inspected module up to date?
 upToDate :: [String] -> InspectedModule -> ExceptT String IO Bool
 upToDate opts (Inspected insp m _) = case m of
 	FileModule f _ -> liftM (== insp) $ fileInspection f opts
-	CabalModule _ _ _ -> return $ insp == browseInspection opts
+	InstalledModule _ _ _ -> return $ insp == browseInspection opts
 	_ -> return False
 
 -- | Rescan inspected module
diff --git a/src/HsDev/Scan/Browse.hs b/src/HsDev/Scan/Browse.hs
--- a/src/HsDev/Scan/Browse.hs
+++ b/src/HsDev/Scan/Browse.hs
@@ -1,26 +1,34 @@
 module HsDev.Scan.Browse (
 	-- * List all packages
-	browsePackages,
+	browsePackages, browsePackagesDeps,
 	-- * Scan cabal modules
-	listModules, browseModules, browse,
+	listModules, browseModules, browse, browseDb,
 	-- * Helpers
-	withPackages, withPackages_, packageDbModules, lookupModule_,
+	withPackages, withPackages_,
+	readPackage, ghcPackageDb, ghcModuleLocation,
+	packageDbCandidate, packageDbCandidate_,
+	packageConfigs, packageDbModules, lookupModule_,
 
 	module Control.Monad.Except
 	) where
 
+import Control.Arrow
 import Control.Lens (view, preview, _Just)
 import Control.Monad.Except
+import Data.List (isPrefixOf)
 import Data.Maybe
 import Data.String (fromString)
+import Data.Version
+import System.Directory
+import System.FilePath
 import Text.Read (readMaybe)
 
-import HsDev.Cabal
+import Data.Deps
+import HsDev.PackageDb
 import HsDev.Symbols
 import HsDev.Tools.Base (inspect)
 import HsDev.Util (liftIOErrors, ordNub)
 
-import Data.Version
 import qualified ConLike as GHC
 import qualified DataCon as GHC
 import qualified DynFlags as GHC
@@ -38,29 +46,45 @@
 import Pretty
 
 -- | Browse packages
-browsePackages :: [String] -> Cabal -> ExceptT String IO [ModulePackage]
-browsePackages opts cabal = liftIOErrors $ withPackages (cabalOpt cabal ++ opts) $ \dflags ->
-	return $ mapMaybe readPackage $ fromMaybe [] $ GHC.pkgDatabase dflags
+browsePackages :: [String] -> PackageDbStack -> ExceptT String IO [ModulePackage]
+browsePackages opts dbs = liftIOErrors $ withPackages_ (packageDbStackOpts dbs ++ opts) $
+	liftM (map readPackage) $ lift packageConfigs
 
-listModules :: [String] -> Cabal -> ExceptT String IO [ModuleLocation]
-listModules opts cabal = liftIOErrors $ withPackages_ (cabalOpt cabal ++ opts) $ do
+-- | Get packages with deps
+browsePackagesDeps :: [String] -> PackageDbStack -> ExceptT String IO (Deps ModulePackage)
+browsePackagesDeps opts dbs = liftIOErrors $ withPackages (packageDbStackOpts dbs ++ opts) $ \df -> do
+	cfgs <- lift packageConfigs
+	return $ mapDeps (toPkg df) $ mconcat $ map (uncurry deps) $
+		map (GHC.installedPackageId &&& GHC.depends) cfgs
+	where
+		toPkg df' = readPackage . GHC.getPackageDetails df' . GHC.resolveInstalledPackageId df'
+
+listModules :: [String] -> PackageDbStack -> ExceptT String IO [ModuleLocation]
+listModules opts dbs = liftIOErrors $ withPackages_ (packageDbStackOpts dbs ++ opts) $ do
 	ms <- lift packageDbModules
-	return $ map (uncurry $ ghcModuleLocation cabal) ms
+	pdbs <- mapM (liftIO . ghcPackageDb . fst) ms
+	return [ghcModuleLocation pdb p m | (pdb, (p, m)) <- zip pdbs ms]
 
-browseModules :: [String] -> Cabal -> [ModuleLocation] -> ExceptT String IO [InspectedModule]
-browseModules opts cabal mlocs = liftIOErrors $ withPackages_ (cabalOpt cabal ++ opts) $ do
+browseModules :: [String] -> PackageDbStack -> [ModuleLocation] -> ExceptT String IO [InspectedModule]
+browseModules opts dbs mlocs = liftIOErrors $ withPackages_ (packageDbStackOpts dbs ++ opts) $ do
 	ms <- lift packageDbModules
-	liftM catMaybes $ mapM (uncurry browseModule') [(p, m) | (p, m) <- ms, ghcModuleLocation cabal p m `elem` mlocs]
+	pdbs <- mapM (liftIO . ghcPackageDb . fst) ms
+	liftM catMaybes $ sequence [browseModule' pdb p m | (pdb, (p, m)) <- zip pdbs ms, ghcModuleLocation pdb p m `elem` mlocs]
 	where
-		browseModule' :: GHC.PackageConfig -> GHC.Module -> ExceptT String GHC.Ghc (Maybe InspectedModule)
-		browseModule' p m = tryT $ inspect (ghcModuleLocation cabal p m) (return $ InspectionAt 0 opts) (browseModule cabal p m)
+		browseModule' :: PackageDb -> GHC.PackageConfig -> GHC.Module -> ExceptT String GHC.Ghc (Maybe InspectedModule)
+		browseModule' pdb p m = tryT $ inspect (ghcModuleLocation pdb p m) (return $ InspectionAt 0 opts) (browseModule pdb p m)
 
--- | Browse all modules
-browse :: [String] -> Cabal -> ExceptT String IO [InspectedModule]
-browse opts cabal = listModules opts cabal >>= browseModules opts cabal
+-- | Browse modules, if third argument is True - browse only modules in top of package-db stack
+browse :: [String] -> PackageDbStack -> ExceptT String IO [InspectedModule]
+browse opts dbs = listModules opts dbs >>= browseModules opts dbs
 
-browseModule :: Cabal -> GHC.PackageConfig -> GHC.Module -> ExceptT String GHC.Ghc Module
-browseModule cabal package m = do
+-- | Browse modules in top of package-db stack
+browseDb :: [String] -> PackageDbStack -> ExceptT String IO [InspectedModule]
+browseDb opts dbs = listModules opts dbs >>= browseModules opts dbs . filter inTop where
+	inTop = (== Just (topPackageDb dbs)) . preview modulePackageDb
+
+browseModule :: PackageDb -> GHC.PackageConfig -> GHC.Module -> ExceptT String GHC.Ghc Module
+browseModule pdb package m = do
 	mi <- lift (GHC.getModuleInfo m) >>= maybe (throwError "Can't find module info") return
 	ds <- mapM (toDecl mi) (GHC.modInfoExports mi)
 	let
@@ -75,7 +99,7 @@
 	where
 		thisLoc = view moduleIdLocation $ mloc m
 		mloc m' = ModuleId (fromString mname') $
-			CabalModule cabal (readPackage package) mname'
+			ghcModuleLocation pdb package m'
 			where
 				mname' = GHC.moduleNameString $ GHC.moduleName m'
 		toDecl minfo n = do
@@ -146,17 +170,62 @@
 tryT :: Monad m => ExceptT e m a -> ExceptT e m (Maybe a)
 tryT act = catchError (liftM Just act) (const $ return Nothing)
 
-readPackage :: GHC.PackageConfig -> Maybe ModulePackage
-readPackage pc = readMaybe $ GHC.packageNameString pc ++ "-" ++ showVersion (GHC.packageVersion pc)
+readPackage :: GHC.PackageConfig -> ModulePackage
+readPackage pc = ModulePackage (GHC.packageNameString pc) (showVersion (GHC.packageVersion pc))
 
-ghcModuleLocation :: Cabal -> GHC.PackageConfig -> GHC.Module -> ModuleLocation
-ghcModuleLocation cabal p m = CabalModule cabal (readPackage p) (GHC.moduleNameString $ GHC.moduleName m)
+ghcModuleLocation :: PackageDb -> GHC.PackageConfig -> GHC.Module -> ModuleLocation
+ghcModuleLocation pdb p m = InstalledModule pdb (Just $ readPackage p) (GHC.moduleNameString $ GHC.moduleName m)
 
+ghcPackageDb :: GHC.PackageConfig -> IO PackageDb
+ghcPackageDb = maybe (return GlobalDb) packageDbCandidate_ . listToMaybe . GHC.libraryDirs
+
+-- | Get package-db for package library directory
+-- Haskish way
+-- global-db - library is in <path>/lib/<package> and there exists <path>/lib/package.conf.d
+-- user-db - library is in cabal user directory
+-- package-db
+--   cabal-sandbox - library in .../.cabal-sandbox/.../<platform-ghc-ver>/<package>
+--     then package-db is .../.cabal-sandbox/<platform-ghc-ver>-package.conf.d
+--   stack (snapshots or .stack-work) - library in <path>/lib/<platform-ghc-ver>/<package>
+--     then package-db is <path>/pkgdb
+packageDbCandidate :: FilePath -> IO (Maybe PackageDb)
+packageDbCandidate fpath = liftM Just (msum [global', user', sandbox', stack']) `mplus` return Nothing where
+	global' = do
+		guard (takeFileName (takeDirectory fpath') == "lib")
+		guardExist (takeDirectory fpath' </> "package.conf.d")
+		return GlobalDb
+	user' = do
+		cabalDir <- getAppUserDataDirectory "cabal"
+		guard (splitDirectories cabalDir `isPrefixOf` splitDirectories fpath')
+		return UserDb
+	sandbox' = do
+		guard (".cabal-sandbox" `elem` splitDirectories fpath')
+		let
+			sandboxPath = joinPath $ reverse $ dropWhile (/= ".cabal-sandbox") $ reverse $ splitDirectories fpath'
+			platform = takeFileName (takeDirectory fpath')
+			dbPath = sandboxPath </> (platform ++ "-packages.conf.d")
+		guardExist dbPath
+		return $ PackageDb dbPath
+	stack' = do
+		guard (takeFileName (takeDirectory (takeDirectory fpath')) == "lib")
+		let
+			pkgDb = takeDirectory (takeDirectory $ takeDirectory fpath') </> "pkgdb"
+		guardExist pkgDb
+		return $ PackageDb pkgDb
+	guardExist = doesDirectoryExist >=> guard
+	fpath' = normalise fpath
+
+-- | Use global as default
+packageDbCandidate_ :: FilePath -> IO PackageDb
+packageDbCandidate_ = packageDbCandidate >=> maybe (return GlobalDb) return
+
+packageConfigs :: GHC.GhcMonad m => m [GHC.PackageConfig]
+packageConfigs = liftM (fromMaybe [] . GHC.pkgDatabase) GHC.getSessionDynFlags
+
 packageDbModules :: GHC.GhcMonad m => m [(GHC.PackageConfig, GHC.Module)]
 packageDbModules = do
+	pkgs <- packageConfigs
 	dflags <- GHC.getSessionDynFlags
-	let
-		pkgs = fromMaybe [] $ GHC.pkgDatabase dflags
 	return [(p, m) |
 		p <- pkgs,
 		mn <- map GHC.exposedName (GHC.exposedModules p),
diff --git a/src/HsDev/Server/Base.hs b/src/HsDev/Server/Base.hs
--- a/src/HsDev/Server/Base.hs
+++ b/src/HsDev/Server/Base.hs
@@ -16,20 +16,24 @@
 import Control.Monad.Except
 import Control.Monad.Reader
 import Data.Default
+import Data.List (intercalate)
 import qualified Data.Map as M
 import Data.Maybe
 import Data.String
 import Data.Text (Text)
 import qualified Data.Text as T (pack, unpack)
-import System.Log.Simple hiding (Level(..), Message(..), Command(..))
+import System.Log.Simple hiding (Level(..), Message(..), Command(..), (%=))
 import qualified System.Log.Simple.Base as Log
 import qualified System.Log.Simple as Log
+import System.Directory (removeDirectoryRecursive, createDirectoryIfMissing)
+import System.FilePath
 
 import qualified Control.Concurrent.FiniteChan as F
 import System.Directory.Paths (canonicalize)
 import qualified System.Directory.Watcher as Watcher
-import Text.Format ((~~), FormatBuild(..))
+import Text.Format ((~~), FormatBuild(..), (%=))
 
+import qualified HsDev.Cache as Cache
 import qualified HsDev.Cache.Structured as SC
 import qualified HsDev.Client.Commands as Client
 import HsDev.Database
@@ -44,9 +48,6 @@
 
 #if mingw32_HOST_OS
 import System.Win32.FileMapping.NamePool
-#else
-import System.Posix.Process
-import System.Posix.IO
 #endif
 
 -- | Inits log chan and returns functions (print message, wait channel)
@@ -73,11 +74,25 @@
 runServer sopts act = bracket (initLog sopts) (\(_, _, _, x) -> x) $ \(logger', outputStr, listenLog, waitOutput) -> Log.scopeLog logger' (T.pack "hsdev") $ Watcher.withWatcher $ \watcher -> do
 	waitSem <- newQSem 0
 	db <- DB.newAsync
+	withCache sopts () $ \cdir -> do
+		outputStr Log.Trace $ "Checking cache version in {}" ~~ cdir 
+		ver <- Cache.readVersion $ cdir </> Cache.versionCache
+		outputStr Log.Debug $ "Cache version: {}" ~~ strVersion ver
+		when (not $ sameVersion (cutVersion version) (cutVersion ver)) $ ignoreIO $ do
+			outputStr Log.Info $ "Cache version ({cache}) is incompatible with hsdev version ({hsdev}), removing cache ({dir})" ~~
+				("cache" %= strVersion ver) ~~
+				("hsdev" %= strVersion version) ~~
+				("dir" %= cdir)
+			-- drop cache
+			removeDirectoryRecursive cdir
+		outputStr Log.Debug $ "Writing new cache version: {}" ~~ strVersion version
+		createDirectoryIfMissing True cdir
+		Cache.writeVersion $ cdir </> Cache.versionCache
 	when (serverLoad sopts) $ withCache sopts () $ \cdir -> do
-		outputStr Log.Info $ "Loading cache from " ++ cdir
+		outputStr Log.Info $ "Loading cache from {}" ~~ cdir
 		dbCache <- liftA merge <$> SC.load cdir
 		case dbCache of
-			Left err -> outputStr Log.Error $ "Failed to load cache: " ++ err
+			Left err -> outputStr Log.Error $ "Failed to load cache: {}" ~~ err
 			Right dbCache' -> DB.update db (return dbCache')
 #if mingw32_HOST_OS
 	mmapPool <- Just <$> createPool "hsdev"
@@ -138,7 +153,7 @@
 		let
 			sd = structurize db
 		liftIO $ SC.dump cdir sd
-		forM_ (M.keys (structuredCabals sd)) $ \c -> Log.log Log.Debug ("cache write: cabal {}" ~~ show c)
+		forM_ (M.keys (structuredPackageDbs sd)) $ \c -> Log.log Log.Debug ("cache write: cabal {}" ~~ show c)
 		forM_ (M.keys (structuredProjects sd)) $ \p -> Log.log Log.Debug ("cache write: project {}" ~~ p)
 		case allModules (structuredFiles sd) of
 			[] -> return ()
@@ -154,7 +169,7 @@
 	where
 		cacheErr e = Log.log Log.Error ("Error reading cache: {}" ~~ e) >> return Nothing
 		cacheOk s = do
-			forM_ (M.keys (structuredCabals s)) $ \c -> Log.log Log.Debug ("cache read: cabal {}" ~~ show c)
+			forM_ (M.keys (structuredPackageDbs s)) $ \c -> Log.log Log.Debug ("cache read: cabal {}" ~~ show c)
 			forM_ (M.keys (structuredProjects s)) $ \p -> Log.log Log.Debug ("cache read: project {}" ~~ p)
 			case allModules (structuredFiles s) of
 				[] -> return ()
diff --git a/src/HsDev/Server/Commands.hs b/src/HsDev/Server/Commands.hs
--- a/src/HsDev/Server/Commands.hs
+++ b/src/HsDev/Server/Commands.hs
@@ -14,7 +14,7 @@
 import Control.Applicative
 import Control.Concurrent
 import Control.Concurrent.Async
-import Control.Exception (SomeException, handle)
+import Control.Exception (SomeException)
 import Control.Lens (set, traverseOf, view, over, Lens', Lens, _1, _2, _Left)
 import Control.Monad
 import Control.Monad.CatchIO
@@ -41,7 +41,7 @@
 import Control.Concurrent.Util
 import qualified Control.Concurrent.FiniteChan as F
 import Data.Lisp
-import Text.Format ((~~))
+import Text.Format ((~~), (%=))
 import System.Directory.Paths
 
 import qualified HsDev.Client.Commands as Client
@@ -61,7 +61,9 @@
 import System.Win32.FileMapping.NamePool
 import System.Win32.PowerShell (escape, quote, quoteDouble)
 #else
+import Control.Exception (handle)
 import System.Posix.Process
+import System.Posix.Files (removeLink)
 import System.Posix.IO
 #endif
 
@@ -85,9 +87,9 @@
 					Right v -> return v
 			_ <- traverse parseData input -- FIXME: Not used!
 
-			s <- makeSocket
+			s <- makeSocket (clientPort copts)
 			addr' <- inet_addr "127.0.0.1"
-			Net.connect s (SockAddrInet (fromIntegral $ clientPort copts) addr')
+			Net.connect s (sockAddr (clientPort copts) addr')
 			bracket (socketToHandle s ReadWriteMode) hClose $ \h -> do
 				L.hPutStrLn h $ encode $ Message Nothing $ Request c curDir noFile (clientTimeout copts) (clientSilent copts)
 				hFlush h
@@ -119,23 +121,23 @@
 		-- start-process foo 'bar baz' ⇒ foo bar baz -- not expected
 		-- start-process foo '"bar baz"' ⇒ foo "bar baz" -- ok
 		biescape = escape quote . escape quoteDouble
-		script = "try {{ start-process {} {} -WindowStyle Hidden -WorkingDirectory {} }} catch {{ $_.Exception, $_.InvocationInfo.Line }}"
-			~~ escape quote myExe
-			~~ intercalate ", " (map biescape args)
-			~~ escape quote curDir
+		script = "try {{ start-process {process} {args} -WindowStyle Hidden -WorkingDirectory {dir} }} catch {{ $_.Exception, $_.InvocationInfo.Line }}"
+			~~ ("process" %= escape quote myExe)
+			~~ ("args" %= intercalate ", " (map biescape args))
+			~~ ("dir" %= escape quote curDir)
 	r <- readProcess "powershell" [
 		"-Command",
 		script] ""
 	if all isSpace r
-		then putStrLn $ "Server started at port " ++ show (serverPort sopts)
+		then putStrLn $ "Server started at port {}" ~~ serverPort sopts
 		else mapM_ putStrLn [
 			"Failed to start server",
-			"\tCommand: " ++ script,
-			"\tResult: " ++ r]
+			"\tCommand: {}" ~~ script,
+			"\tResult: {}" ~~ r]
 #else
 	let
 		forkError :: SomeException -> IO ()
-		forkError e  = putStrLn $ "Failed to start server: " ++ show e
+		forkError e  = putStrLn $ "Failed to start server: {}" ~~ show e
 
 		proxy :: IO ()
 		proxy = do
@@ -156,17 +158,18 @@
 		putStrLn $ "Server started at port {}" ~~ serverPort sopts
 #endif
 runServerCommand (Run sopts) = runServer sopts $ do
-	Log.log Log.Info $ "Server started at port {}" ~~ serverPort sopts
+	q <- liftIO $ newQSem 0
 	clientChan <- liftIO F.newChan
 	session <- getSession
 	_ <- liftIO $ async $ withSession session $ Log.scope "listener" $ flip finally serverExit $
-		bracket (liftIO makeSocket) (liftIO . close) $ \s -> do
+		bracket (liftIO $ makeSocket (serverPort sopts)) (liftIO . close) $ \s -> do
 			liftIO $ do
 				setSocketOption s ReuseAddr 1
-				bind s $ SockAddrInet (fromIntegral $ serverPort sopts) iNADDR_ANY
+				bind s $ sockAddr (serverPort sopts) iNADDR_ANY
 				listen s maxListenQueue
 			forever $ logAsync (Log.log Log.Fatal . fromString) $ logIO "exception: " (Log.log Log.Error . fromString) $ do
 				Log.log Log.Trace "accepting connection"
+				liftIO $ signalQSem q
 				s' <- liftIO $ fst <$> accept s
 				Log.log Log.Trace $ "accepted {}" ~~ show s'
 				void $ liftIO $ forkIO $ withSession session $ Log.scope (T.pack $ show s') $
@@ -186,9 +189,13 @@
 								liftIO $ F.putChan clientChan timeoutWait
 								processClientSocket s'
 
+	Log.log Log.Trace "waiting for starting accept thread"
+	liftIO $ waitQSem q
+	Log.log Log.Info $ "Server started at port {}" ~~ serverPort sopts
 	Log.log Log.Trace "waiting for accept thread"
 	serverWait
 	Log.log Log.Trace "accept thread stopped"
+	liftIO $ unlink (serverPort sopts)
 	askSession sessionDatabase >>= liftIO . DB.readAsync >>= writeCache sopts
 	Log.log Log.Trace "waiting for clients"
 	liftIO (F.stopChan clientChan) >>= sequence_
@@ -196,9 +203,9 @@
 runServerCommand (Stop copts) = runServerCommand (Remote copts False Exit)
 runServerCommand (Connect copts) = do
 	curDir <- getCurrentDirectory
-	s <- makeSocket
+	s <- makeSocket $ clientPort copts
 	addr' <- inet_addr "127.0.0.1"
-	Net.connect s (SockAddrInet (fromIntegral $ clientPort copts) addr')
+	Net.connect s $ sockAddr (clientPort copts) addr'
 	bracket (socketToHandle s ReadWriteMode) hClose $ \h -> forM_ [(1 :: Integer)..] $ \i -> ignoreIO $ do
 		input' <- hGetLineBS stdin
 		case decodeMsg input' of
@@ -215,7 +222,9 @@
 			Left em -> putStrLn $ "Can't decode response: {}" ~~ view msg em
 			Right m -> do
 				Response r' <- unMmap $ view (msg . message) m
-				putStrLn $ "{}: {}" ~~ fromMaybe "_" (view (msg . messageId) m) ~~ fromUtf8 (encodeMsg $ set msg (Response r') m)
+				putStrLn $ "{id}: {response}"
+					~~ ("id" %= fromMaybe "_" (view (msg . messageId) m))
+					~~ ("response" %= fromUtf8 (encodeMsg $ set msg (Response r') m))
 				case unResponse (view (msg . message) m) of
 					Left _ -> waitResp h
 					_ -> return ()
@@ -412,5 +421,18 @@
 #endif
 unMmap r = return r
 
-makeSocket :: IO Socket
-makeSocket = socket AF_INET Stream defaultProtocol
+makeSocket :: ConnectionPort -> IO Socket
+makeSocket (NetworkPort _) = socket AF_INET Stream defaultProtocol
+makeSocket (UnixPort _) = socket AF_UNIX Stream defaultProtocol
+
+sockAddr :: ConnectionPort -> HostAddress -> SockAddr
+sockAddr (NetworkPort p) addr = SockAddrInet (fromIntegral p) addr
+sockAddr (UnixPort s) _ = SockAddrUnix s
+
+unlink :: ConnectionPort -> IO ()
+unlink (NetworkPort _) = return ()
+#if mingw32_HOST_OS
+unlink (UnixPort _) = return ()
+#else
+unlink (UnixPort s) = removeLink s
+#endif
diff --git a/src/HsDev/Server/Types.hs b/src/HsDev/Server/Types.hs
--- a/src/HsDev/Server/Types.hs
+++ b/src/HsDev/Server/Types.hs
@@ -6,7 +6,7 @@
 	Session(..), SessionMonad(..), askSession, ServerM(..),
 	CommandOptions(..), CommandError(..), commandErrorMsg, commandErrorDetails, commandError, commandError_, CommandMonad(..), askOptions, ClientM(..),
 	withSession, serverListen, serverWait, serverUpdateDB, serverWriteCache, serverReadCache, serverExit, commandRoot, commandNotify, commandLink, commandHold,
-	ServerCommand(..), ServerOpts(..), ClientOpts(..), serverOptsArgs, Request(..),
+	ServerCommand(..), ConnectionPort(..), ServerOpts(..), ClientOpts(..), serverOptsArgs, Request(..),
 
 	Command(..), AddedContents(..),
 	GhcModCommand(..),
@@ -32,10 +32,12 @@
 import System.Log.Simple hiding (Command)
 
 import System.Directory.Paths
+import Text.Format (FormatBuild(..))
 
 import HsDev.Database
 import qualified HsDev.Database.Async as DB
 import HsDev.Project
+import HsDev.Sandbox
 import HsDev.Symbols
 import HsDev.Server.Message
 import HsDev.Watcher.Types (Watcher)
@@ -214,9 +216,20 @@
 	Remote ClientOpts Bool Command
 		deriving (Show)
 
+data ConnectionPort = NetworkPort Int | UnixPort String deriving (Eq, Read)
+
+instance Default ConnectionPort where
+	def = NetworkPort 4567
+
+instance Show ConnectionPort where
+	show (NetworkPort p) = show p
+	show (UnixPort s) = "unix " ++ s
+
+instance FormatBuild ConnectionPort
+
 -- | Server options
 data ServerOpts = ServerOpts {
-	serverPort :: Int,
+	serverPort :: ConnectionPort,
 	serverTimeout :: Int,
 	serverLog :: Maybe FilePath,
 	serverLogConfig :: String,
@@ -225,11 +238,11 @@
 		deriving (Show)
 
 instance Default ServerOpts where
-	def = ServerOpts 4567 0 Nothing "use default" Nothing False
+	def = ServerOpts def 0 Nothing "use default" Nothing False
 
 -- | Client options
 data ClientOpts = ClientOpts {
-	clientPort :: Int,
+	clientPort :: ConnectionPort,
 	clientPretty :: Bool,
 	clientStdin :: Bool,
 	clientTimeout :: Int,
@@ -237,7 +250,7 @@
 		deriving (Show)
 
 instance Default ClientOpts where
-	def = ClientOpts 4567 False False 0 False
+	def = ClientOpts def False False 0 False
 
 instance FromCmd ServerCommand where
 	cmdP = serv <|> remote where
@@ -251,7 +264,7 @@
 
 instance FromCmd ServerOpts where
 	cmdP = ServerOpts <$>
-		(portArg <|> pure (serverPort def)) <*>
+		(connectionArg <|> pure (serverPort def)) <*>
 		(timeoutArg <|> pure (serverTimeout def)) <*>
 		optional logArg <*>
 		(logConfigArg <|> pure (serverLogConfig def)) <*>
@@ -260,13 +273,14 @@
 
 instance FromCmd ClientOpts where
 	cmdP = ClientOpts <$>
-		(portArg <|> pure (clientPort def)) <*>
+		(connectionArg <|> pure (clientPort def)) <*>
 		prettyFlag <*>
 		stdinFlag <*>
 		(timeoutArg <|> pure (clientTimeout def)) <*>
 		silentFlag
 
-portArg :: Parser Int
+portArg :: Parser ConnectionPort
+connectionArg :: Parser ConnectionPort
 timeoutArg :: Parser Int
 logArg :: Parser FilePath
 logConfigArg :: Parser String
@@ -277,7 +291,14 @@
 stdinFlag :: Parser Bool
 silentFlag :: Parser Bool
 
-portArg = option auto (long "port" <> metavar "number" <> help "connection port")
+portArg = NetworkPort <$> option auto (long "port" <> metavar "number" <> help "connection port")
+#if mingw32_HOST_OS
+connectionArg = portArg
+#else
+unixArg :: Parser ConnectionPort
+unixArg = UnixPort <$> strOption (long "unix" <> metavar "name" <> help "unix connection port")
+connectionArg = portArg <|> unixArg
+#endif
 timeoutArg = option auto (long "timeout" <> metavar "msec" <> help "query timeout")
 logArg = strOption (long "log" <> short 'l' <> metavar "file" <> help "log file")
 logConfigArg = strOption (long "log-config" <> metavar "rule" <> help "log config: low [low], high [high], set [low] [high], use [default/debug/trace/silent/supress]")
@@ -290,7 +311,7 @@
 
 serverOptsArgs :: ServerOpts -> [String]
 serverOptsArgs sopts = concat [
-	["--port", show $ serverPort sopts],
+	portArgs (serverPort sopts),
 	["--timeout", show $ serverTimeout sopts],
 	marg "--log" (serverLog sopts),
 	["--log-config", serverLogConfig sopts],
@@ -300,6 +321,9 @@
 		marg :: String -> Maybe String -> [String]
 		marg n (Just v) = [n, v]
 		marg _ _ = []
+		portArgs :: ConnectionPort -> [String]
+		portArgs (NetworkPort n) = ["--port", show n]
+		portArgs (UnixPort s) = ["--unix", s]
 
 data Request = Request {
 	requestCommand :: Command,
@@ -327,7 +351,8 @@
 	AddData { addedContents :: [AddedContents] } |
 	Scan {
 		scanProjects :: [FilePath],
-		scanSandboxes :: [Cabal],
+		scanCabal :: Bool,
+		scanSandboxes :: [FilePath],
 		scanFiles :: [FilePath],
 		scanPaths :: [FilePath],
 		scanContents :: [FileContents],
@@ -344,7 +369,8 @@
 		inferModules :: [String] } |
 	Remove {
 		removeProjects :: [FilePath],
-		removeSandboxes :: [Cabal],
+		removeCabal :: Bool,
+		removeSandboxes :: [FilePath],
 		removeFiles :: [FilePath] } |
 	RemoveAll |
 	InfoModules [TargetFilter] |
@@ -416,7 +442,9 @@
 	TargetFile FilePath |
 	TargetModule String |
 	TargetDepsOf String |
-	TargetCabal Cabal |
+	TargetPackageDb PackageDb |
+	TargetCabal |
+	TargetSandbox FilePath |
 	TargetPackage String |
 	TargetSourced |
 	TargetStandalone
@@ -425,8 +453,9 @@
 data SearchType = SearchExact | SearchPrefix | SearchInfix | SearchSuffix | SearchRegex deriving (Show)
 
 instance Paths Command where
-	paths f (Scan projs cs fs ps fcts ghcs docs infer) = Scan <$>
+	paths f (Scan projs c cs fs ps fcts ghcs docs infer) = Scan <$>
 		each f projs <*>
+		pure c <*>
 		(each . paths) f cs <*>
 		each f fs <*>
 		each f ps <*>
@@ -436,7 +465,7 @@
 		pure infer
 	paths f (RefineDocs projs fs ms) = RefineDocs <$> each f projs <*> each f fs <*> pure ms
 	paths f (InferTypes projs fs ms) = InferTypes <$> each f projs <*> each f fs <*> pure ms
-	paths f (Remove projs cs fs) = Remove <$> each f projs <*> (each . paths) f cs <*> each f fs
+	paths f (Remove projs c cs fs) = Remove <$> each f projs <*> pure c <*> (each . paths) f cs <*> each f fs
 	paths _ RemoveAll = pure RemoveAll
 	paths f (InfoModules t) = InfoModules <$> paths f t
 	paths f (InfoSymbol q t l) = InfoSymbol <$> pure q <*> paths f t <*> pure l
@@ -468,7 +497,8 @@
 
 instance Paths TargetFilter where
 	paths f (TargetFile fpath) = TargetFile <$> f fpath
-	paths f (TargetCabal c) = TargetCabal <$> paths f c
+	paths f (TargetPackageDb pdb) = TargetPackageDb <$> paths f pdb
+	paths f (TargetSandbox c) = TargetSandbox <$> paths f c
 	paths _ t = pure t
 
 instance Paths [TargetFilter] where
@@ -481,7 +511,8 @@
 		cmd "add" "add info to database" (AddData <$> option readJSON idm),
 		cmd "scan" "scan sources" $ Scan <$>
 			many projectArg <*>
-			many cabalArg <*>
+			cabalFlag <*>
+			many sandboxArg <*>
 			many fileArg <*>
 			many (pathArg $ help "path") <*>
 			many cmdP <*>
@@ -492,7 +523,8 @@
 		cmd "infer" "infer types" $ InferTypes <$> many projectArg <*> many fileArg <*> many moduleArg,
 		cmd "remove" "remove modules info" $ Remove <$>
 			many projectArg <*>
-			many cabalArg <*>
+			cabalFlag <*>
+			many sandboxArg <*>
 			many fileArg,
 		cmd "remove-all" "remove all data" (pure RemoveAll),
 		cmd "modules" "list modules" (InfoModules <$> many cmdP),
@@ -543,7 +575,17 @@
 	cmdP = option readJSON (long "contents")
 
 instance FromCmd TargetFilter where
-	cmdP = asum [TargetProject <$> projectArg, TargetFile <$> fileArg, TargetModule <$> moduleArg, TargetDepsOf <$> depsArg, TargetCabal <$> cabalArg, TargetPackage <$> packageArg, flag' TargetSourced (long "src"), flag' TargetStandalone (long "stand")]
+	cmdP = asum [
+		TargetProject <$> projectArg,
+		TargetFile <$> fileArg,
+		TargetModule <$> moduleArg,
+		TargetDepsOf <$> depsArg,
+		TargetPackageDb <$> packageDbArg,
+		flag' TargetCabal (long "cabal"),
+		TargetSandbox <$> sandboxArg,
+		TargetPackage <$> packageArg,
+		flag' TargetSourced (long "src"),
+		flag' TargetStandalone (long "stand")]
 
 instance FromCmd SearchQuery where
 	cmdP = SearchQuery <$> (strArgument idm <|> pure "") <*> asum [
@@ -556,7 +598,7 @@
 readJSON :: FromJSON a => ReadM a
 readJSON = str >>= maybe (readerError "Can't parse JSON argument") return . decode . L.pack
 
-cabalArg :: Parser Cabal
+cabalFlag :: Parser Bool
 ctx :: Parser FilePath
 depsArg :: Parser String
 docsFlag :: Parser Bool
@@ -575,10 +617,10 @@
 pathArg :: Mod OptionFields String -> Parser FilePath
 projectArg :: Parser String
 pureFlag :: Parser Bool
-sandboxArg :: Parser String
+sandboxArg :: Parser FilePath
 wideFlag :: Parser Bool
 
-cabalArg = flag' Cabal (long "cabal") <|> (Sandbox <$> sandboxArg)
+cabalFlag = switch (long "cabal")
 ctx = fileArg
 depsArg = strOption (long "deps" <> metavar "object" <> help "filter to such that in dependency of specified object (file or project)")
 docsFlag = switch (long "docs" <> help "scan source file docs")
@@ -594,6 +636,10 @@
 localsFlag = switch (long "locals" <> short 'l' <> help "look in local declarations")
 moduleArg = strOption (long "module" <> metavar "name" <> short 'm' <> help "module name")
 packageArg = strOption (long "package" <> metavar "name" <> help "module package")
+packageDbArg =
+	flag' GlobalDb (long "global-db" <> help "global package-db") <|>
+	flag' UserDb (long "user-db" <> help "user package-db") <|>
+	(PackageDb <$> strOption (long "package-db" <> metavar "path" <> help "custom package-db"))
 pathArg f = strOption (long "path" <> metavar "path" <> short 'p' <> f)
 projectArg = strOption (long "project" <> long "proj" <> metavar "project")
 pureFlag = switch (long "pure" <> help "don't modify actual file, just return result")
@@ -604,9 +650,10 @@
 	toJSON Ping = cmdJson "ping" []
 	toJSON Listen = cmdJson "listen" []
 	toJSON (AddData cts) = cmdJson "add" ["data" .= cts]
-	toJSON (Scan projs cabals fs ps contents ghcs docs' infer') = cmdJson "scan" [
+	toJSON (Scan projs cabal sboxes fs ps contents ghcs docs' infer') = cmdJson "scan" [
 		"projects" .= projs,
-		"sandboxes" .= cabals,
+		"cabal" .= cabal,
+		"sandboxes" .= sboxes,
 		"files" .= fs,
 		"paths" .= ps,
 		"contents" .= contents,
@@ -615,7 +662,7 @@
 		"infer" .= infer']
 	toJSON (RefineDocs projs fs ms) = cmdJson "docs" ["projects" .= projs, "files" .= fs, "modules" .= ms]
 	toJSON (InferTypes projs fs ms) = cmdJson "infer" ["projects" .= projs, "files" .= fs, "modules" .= ms]
-	toJSON (Remove projs cabals fs) = cmdJson "remove" ["projects" .= projs, "sandboxes" .= cabals, "files" .= fs]
+	toJSON (Remove projs cabal sboxes fs) = cmdJson "remove" ["projects" .= projs, "cabal" .= cabal, "sandboxes" .= sboxes, "files" .= fs]
 	toJSON RemoveAll = cmdJson "remove-all" []
 	toJSON (InfoModules tf) = cmdJson "modules" ["filters" .= tf]
 	toJSON InfoPackages = cmdJson "packages" []
@@ -650,6 +697,7 @@
 		guardCmd "add" v *> (AddData <$> v .:: "data"),
 		guardCmd "scan" v *> (Scan <$>
 			v .::?! "projects" <*>
+			(v .:: "cabal" <|> pure False) <*>
 			v .::?! "sandboxes" <*>
 			v .::?! "files" <*>
 			v .::?! "paths" <*>
@@ -661,6 +709,7 @@
 		guardCmd "infer" v *> (InferTypes <$> v .::?! "projects" <*> v .::?! "files" <*> v .::?! "modules"),
 		guardCmd "remove" v *> (Remove <$>
 			v .::?! "projects" <*>
+			(v .:: "cabal" <|> pure False) <*>
 			v .::?! "sandboxes" <*>
 			v .::?! "files"),
 		guardCmd "remove-all" v *> pure RemoveAll,
@@ -738,7 +787,9 @@
 	toJSON (TargetFile fpath) = object ["file" .= fpath]
 	toJSON (TargetModule mname) = object ["module" .= mname]
 	toJSON (TargetDepsOf dep) = object ["deps" .= dep]
-	toJSON (TargetCabal cabal) = object ["cabal" .= cabal]
+	toJSON (TargetPackageDb pdb) = object ["db" .= pdb]
+	toJSON TargetCabal = toJSON ("cabal" :: String)
+	toJSON (TargetSandbox sbox) = object ["sandbox" .= sbox]
 	toJSON (TargetPackage pname) = object ["package" .= pname]
 	toJSON TargetSourced = toJSON ("sourced" :: String)
 	toJSON TargetStandalone = toJSON ("standalone" :: String)
@@ -750,11 +801,13 @@
 			TargetFile <$> v .:: "file",
 			TargetModule <$> v .:: "module",
 			TargetDepsOf <$> v .:: "deps",
-			TargetCabal <$> v .:: "cabal",
+			TargetPackageDb <$> v .:: "db",
+			TargetSandbox <$> v .:: "sandbox",
 			TargetPackage <$> v .:: "package"]
 		str' = do
 			s <- parseJSON j :: A.Parser String
 			case s of
+				"cabal" -> return TargetCabal
 				"sourced" -> return TargetSourced
 				"standalone" -> return TargetStandalone
 				_ -> empty
diff --git a/src/HsDev/Stack.hs b/src/HsDev/Stack.hs
new file mode 100644
--- /dev/null
+++ b/src/HsDev/Stack.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE TemplateHaskell, RankNTypes #-}
+
+module HsDev.Stack (
+	stack, yaml,
+	path, pathOf,
+	build, buildDeps, configure,
+	StackEnv(..), stackRoot, stackProject, stackConfig, stackGhc, stackSnapshot, stackLocal,
+	getStackEnv, projectEnv,
+	stackPackageDbStack,
+
+	MaybeT(..)
+	) where
+
+import Control.Arrow
+import Control.Lens (makeLenses, Lens', at, ix, lens, (^?), (^.), view)
+import Control.Monad
+import Control.Monad.Trans.Maybe
+import Control.Monad.IO.Class
+import Data.Char
+import Data.Maybe
+import Data.Map (Map)
+import qualified Data.Map as M
+import System.Directory
+import System.Environment
+import System.FilePath
+import System.Process
+
+import HsDev.PackageDb
+import HsDev.Project
+import HsDev.Util (withCurrentDirectory)
+
+-- | Invoke stack command, we are trying to get actual stack near current hsdev executable
+stack :: [String] -> MaybeT IO String
+stack cmd = do
+	curExe <- liftIO getExecutablePath
+	withCurrentDirectory (takeDirectory curExe) $ do
+		stackExe <- MaybeT $ findExecutable "stack"
+		liftIO $ readProcess stackExe cmd ""
+
+-- | Make yaml opts
+yaml :: Maybe FilePath -> [String]
+yaml Nothing = []
+yaml (Just y) = ["--stack-yaml", y]
+
+type Paths = Map String FilePath
+
+-- | Stack path
+path :: Maybe FilePath -> MaybeT IO Paths
+path mcfg = liftM (M.fromList . map breakPath . lines) $ stack ("path" : yaml mcfg) where
+	breakPath :: String -> (String, FilePath)
+	breakPath = second (dropWhile isSpace . drop 1) . break (== ':')
+
+-- | Get path for
+pathOf :: String -> Lens' Paths (Maybe FilePath)
+pathOf = at
+
+-- | Build stack project
+build :: [String] -> Maybe FilePath -> MaybeT IO ()
+build opts mcfg = void $ stack $ "build" : (opts ++ yaml mcfg)
+
+-- | Build only dependencies
+buildDeps :: Maybe FilePath -> MaybeT IO ()
+buildDeps = build ["--only-dependencies"]
+
+-- | Configure project
+configure :: Maybe FilePath -> MaybeT IO ()
+configure = build ["--only-configure"]
+
+data StackEnv = StackEnv {
+	_stackRoot :: FilePath,
+	_stackProject :: FilePath,
+	_stackConfig :: FilePath,
+	_stackGhc :: FilePath,
+	_stackSnapshot :: FilePath,
+	_stackLocal :: FilePath }
+
+makeLenses ''StackEnv
+
+getStackEnv :: Paths -> Maybe StackEnv
+getStackEnv p = StackEnv <$>
+	(p ^. pathOf "global-stack-root") <*>
+	(p ^. pathOf "project-root") <*>
+	(p ^. pathOf "config-location") <*>
+	(p ^. pathOf "ghc-paths") <*>
+	(p ^. pathOf "snapshot-pkg-db") <*>
+	(p ^. pathOf "local-pkg-db")
+
+-- | Projects paths
+projectEnv :: FilePath -> MaybeT IO StackEnv
+projectEnv p = do
+	hasConfig <- liftIO $ doesFileExist yaml
+	guard hasConfig
+	paths' <- path (Just yaml)
+	MaybeT $ return $ getStackEnv paths'
+	where
+		yaml = p </> "stack.yaml"
+
+-- | Get package-db stack for stack environment
+stackPackageDbStack :: Lens' StackEnv PackageDbStack
+stackPackageDbStack = lens g s where
+	g :: StackEnv -> PackageDbStack
+	g env' = PackageDbStack $ map PackageDb [_stackLocal env', _stackSnapshot env']
+	s :: StackEnv -> PackageDbStack -> StackEnv
+	s env' pdbs = env' {
+		_stackSnapshot = fromMaybe (_stackSnapshot env') $ pdbs ^? packageDbStack . ix 1 . packageDb,
+		_stackLocal = fromMaybe (_stackLocal env') $ pdbs ^? packageDbStack . ix 0 . packageDb }
diff --git a/src/HsDev/Symbols.hs b/src/HsDev/Symbols.hs
--- a/src/HsDev/Symbols.hs
+++ b/src/HsDev/Symbols.hs
@@ -37,18 +37,20 @@
 
 import Control.Applicative
 import Control.Arrow
-import Control.Lens (view, set, over)
+import Control.Lens
 import Control.Monad.Trans.Maybe
 import Control.Monad.Except
 import Data.Function (on)
 import Data.List
 import Data.Maybe (fromMaybe)
+import qualified Data.Map as M
 import Data.Ord (comparing)
 import Data.Text (Text)
 import qualified Data.Text as T (concat)
 import System.Directory
 import System.FilePath
 
+import Data.Deps
 import System.Directory.Paths
 
 import HsDev.Symbols.Types
@@ -166,16 +168,12 @@
 		merge' [] = error "mergeExported: impossible"
 		merge' ds@(d:_) = ExportedDeclaration (map (view declarationModuleId) ds) (view moduleDeclaration d)
 
-instance Paths Cabal where
-	paths _ Cabal = pure Cabal
-	paths f (Sandbox p) = Sandbox <$> f p
-
 instance Paths Project where
 	paths f (Project nm p c desc) = Project nm <$> f p <*> f c <*> pure desc
 
 instance Paths ModuleLocation where
 	paths f (FileModule fpath p) = FileModule <$> f fpath <*> traverse (paths f) p
-	paths f (CabalModule c p n) = CabalModule <$> paths f c <*> pure p <*> pure n
+	paths f (InstalledModule c p n) = InstalledModule <$> paths f c <*> pure p <*> pure n
 	paths _ (ModuleSource m) = pure $ ModuleSource m
 
 -- | Find project file is related to
@@ -210,18 +208,20 @@
 moduleOpts :: [ModulePackage] -> Module -> [String]
 moduleOpts pkgs m = case view moduleLocation m of
 	FileModule file proj -> concat [
-		["-i" ++ s | s <- srcDirs],
-		concatMap extensionsOpts exts,
 		hidePackages,
-		["-package " ++ p | p <- deps, p `elem` pkgs']]
+		targetOpts info']
 		where
 			infos' = maybe [] (`fileTargets` file) proj
-			srcDirs = concatMap (view infoSourceDirs) infos'
-			exts = map (file `withExtensions`) infos'
-			deps = concatMap (view infoDepends) infos'
-			pkgs' = map (view packageName) pkgs
+			info' = over infoDepends (filter validDep) (mconcat $ selfInfo : infos')
+			selfInfo
+				| proj ^? _Just . projectName `elem` map Just (infos' ^.. each . infoDepends . each) = fromMaybe mempty $
+					proj ^? _Just . projectDescription . _Just . projectLibrary . _Just . libraryBuildInfo
+				| otherwise = mempty
+			-- filter out unavailable packages such as unix under windows
+			validDep d = d `elem` pkgs'
+			pkgs' = pkgs ^.. each . packageName
 			hidePackages
-				| null infos' = []
+				| null (info' ^. infoDepends) = []
 				| otherwise = ["-hide-all-packages"]
 	_ -> []
 
diff --git a/src/HsDev/Symbols/Location.hs b/src/HsDev/Symbols/Location.hs
--- a/src/HsDev/Symbols/Location.hs
+++ b/src/HsDev/Symbols/Location.hs
@@ -6,7 +6,7 @@
 	Location(..),
 
 	packageName, packageVersion,
-	moduleFile, moduleProject, moduleCabal, modulePackage, cabalModuleName, moduleSourceName,
+	moduleFile, moduleProject, modulePackageDb, modulePackage, cabalModuleName, moduleSourceName,
 	positionLine, positionColumn,
 	regionFrom, regionTo,
 	locationModule, locationPosition,
@@ -16,7 +16,7 @@
 	packageOpt,
 	RecalcTabs(..),
 
-	module HsDev.Cabal
+	module HsDev.PackageDb
 	) where
 
 import Control.Applicative
@@ -32,10 +32,11 @@
 import System.FilePath
 import Text.Read (readMaybe)
 
-import HsDev.Cabal
+import HsDev.PackageDb
 import HsDev.Project
 import HsDev.Util ((.::), (.::?))
 
+-- | Just package name and version without its location
 data ModulePackage = ModulePackage {
 	_packageName :: String,
 	_packageVersion :: String }
@@ -74,7 +75,7 @@
 -- | Location of module
 data ModuleLocation =
 	FileModule { _moduleFile :: FilePath, _moduleProject :: Maybe Project } |
-	CabalModule { _moduleCabal :: Cabal, _modulePackage :: Maybe ModulePackage, _cabalModuleName :: String } |
+	InstalledModule { _modulePackageDb :: PackageDb, _modulePackage :: Maybe ModulePackage, _cabalModuleName :: String } |
 	ModuleSource { _moduleSourceName :: Maybe String }
 		deriving (Eq, Ord)
 
@@ -85,29 +86,29 @@
 
 locationId :: ModuleLocation -> String
 locationId (FileModule fpath _) = fpath
-locationId (CabalModule cabal mpack nm) = intercalate ":" [show cabal, maybe "" show mpack, nm]
+locationId (InstalledModule cabal mpack nm) = intercalate ":" [show cabal, maybe "" show mpack, nm]
 locationId (ModuleSource msrc) = fromMaybe "" msrc
 
 instance NFData ModuleLocation where
 	rnf (FileModule f p) = rnf f `seq` rnf p
-	rnf (CabalModule c p n) = rnf c `seq` rnf p `seq` rnf n
+	rnf (InstalledModule d p n) = rnf d `seq` rnf p `seq` rnf n
 	rnf (ModuleSource m) = rnf m
 
 instance Show ModuleLocation where
 	show (FileModule f p) = f ++ maybe "" (" in " ++) (fmap (view projectPath) p)
-	show (CabalModule _ p n) = n ++ maybe "" (" in package " ++) (fmap show p)
+	show (InstalledModule _ p n) = n ++ maybe "" (" in package " ++) (fmap show p)
 	show (ModuleSource m) = fromMaybe "" m
 
 instance ToJSON ModuleLocation where
 	toJSON (FileModule f p) = object ["file" .= f, "project" .= fmap (view projectCabal) p]
-	toJSON (CabalModule c p n) = object ["cabal" .= c, "package" .= fmap show p, "name" .= n]
+	toJSON (InstalledModule c p n) = object ["db" .= c, "package" .= fmap show p, "name" .= n]
 	toJSON (ModuleSource (Just s)) = object ["source" .= s]
 	toJSON (ModuleSource Nothing) = object []
 
 instance FromJSON ModuleLocation where
 	parseJSON = withObject "module location" $ \v ->
 		(FileModule <$> v .:: "file" <*> (fmap project <$> (v .:: "project"))) <|>
-		(CabalModule <$> v .:: "cabal" <*> fmap (join . fmap readMaybe) (v .:: "package") <*> v .:: "name") <|>
+		(InstalledModule <$> v .:: "db" <*> fmap (join . fmap readMaybe) (v .:: "package") <*> v .:: "name") <|>
 		(ModuleSource <$> v .::? "source")
 
 noLocation :: ModuleLocation
diff --git a/src/HsDev/Symbols/Resolve.hs b/src/HsDev/Symbols/Resolve.hs
--- a/src/HsDev/Symbols/Resolve.hs
+++ b/src/HsDev/Symbols/Resolve.hs
@@ -65,7 +65,7 @@
 resolveModule :: Module -> ResolveM ResolvedModule
 resolveModule m = gets (M.lookup $ view moduleId m) >>= maybe resolveModule' return where
 	resolveModule' = save $ case view moduleLocation m of
-		CabalModule {} -> return ResolvedModule {
+		InstalledModule {} -> return ResolvedModule {
 			_resolvedModule = m,
 			_resolvedScope = view moduleDeclarations m,
 			_resolvedExports = view moduleDeclarations m }
@@ -125,12 +125,12 @@
 				case proj' of
 					Nothing -> selectImport i [
 						inFile $ importedModulePath (view moduleName m) file (view importModuleName i),
-						byCabal]
+						installed]
 					Just p -> selectImport i [
 						inProject p,
 						inDepsOf' file p]
-			CabalModule cabal _ _ -> selectImport i [inCabal cabal]
-			ModuleSource _ -> selectImport i [byCabal]
+			InstalledModule cabal _ _ -> selectImport i [inPackageDb cabal]
+			ModuleSource _ -> selectImport i [installed]
 		fromMaybe [] <$> traverse (liftM (filterImportList . view resolvedExports) . resolveModule) ms
 	setImport :: Import -> Declaration -> Declaration
 	setImport i' = set declarationImported (Just [i'])
diff --git a/src/HsDev/Symbols/Types.hs b/src/HsDev/Symbols/Types.hs
--- a/src/HsDev/Symbols/Types.hs
+++ b/src/HsDev/Symbols/Types.hs
@@ -28,7 +28,7 @@
 	exportedBy, exportedDeclaration,
 	inspectionAt, inspectionOpts, inspection, inspectedId, inspectionResult,
 
-	module HsDev.Cabal,
+	module HsDev.PackageDb,
 	module HsDev.Project,
 	module HsDev.Symbols.Class,
 	module HsDev.Symbols.Documented
@@ -46,7 +46,7 @@
 import qualified Data.Text as T
 import Data.Time.Clock.POSIX (POSIXTime)
 
-import HsDev.Cabal
+import HsDev.PackageDb
 import HsDev.Project
 import HsDev.Symbols.Class
 import HsDev.Symbols.Documented
@@ -487,7 +487,7 @@
 		showError :: String -> String
 		showError e = unlines $ ("\terror: " ++ e) : case mi of
 			FileModule f p -> ["file: " ++ f, "project: " ++ maybe "" (view projectPath) p]
-			CabalModule c p n -> ["cabal: " ++ show c, "package: " ++ maybe "" show p, "name: " ++ n]
+			InstalledModule c p n -> ["cabal: " ++ show c, "package: " ++ maybe "" show p, "name: " ++ n]
 			ModuleSource src -> ["source: " ++ fromMaybe "" src]
 
 instance ToJSON InspectedModule where
diff --git a/src/HsDev/Symbols/Util.hs b/src/HsDev/Symbols/Util.hs
--- a/src/HsDev/Symbols/Util.hs
+++ b/src/HsDev/Symbols/Util.hs
@@ -1,6 +1,6 @@
 module HsDev.Symbols.Util (
-	projectOf, cabalOf, packageOf,
-	inProject, inDepsOfTarget, inDepsOfFile, inDepsOfProject, inCabal, inPackage, inVersion, inFile, inModuleSource, inModule, byFile, byCabal, standalone,
+	projectOf, packageDbOf, packageOf,
+	inProject, inDepsOfTarget, inDepsOfFile, inDepsOfProject, inPackageDb, inPackageDbStack, inPackage, inVersion, inFile, inModuleSource, inModule, byFile, installed, standalone,
 	imports, qualifier, imported, visible, inScope,
 	newestPackage,
 	sourceModule, visibleModule, preferredModule, uniqueModules,
@@ -27,15 +27,15 @@
 	_ -> Nothing
 
 -- | Get module cabal
-cabalOf :: ModuleId -> Maybe Cabal
-cabalOf m = case view moduleIdLocation m of
-	CabalModule c _ _ -> Just c
+packageDbOf :: ModuleId -> Maybe PackageDb
+packageDbOf m = case view moduleIdLocation m of
+	InstalledModule c _ _ -> Just c
 	_ -> Nothing
 
 -- | Get module package
 packageOf :: ModuleId -> Maybe ModulePackage
 packageOf m = case view moduleIdLocation m of
-	CabalModule _ package _ -> package
+	InstalledModule _ package _ -> package
 	_ -> Nothing
 
 -- | Check if module in project
@@ -56,21 +56,27 @@
 	anyPackage :: [String] -> ModuleId -> Bool
 	anyPackage = liftM or . mapM inPackage
 
--- | Check if module in cabal
-inCabal :: Cabal -> ModuleId -> Bool
-inCabal c m = case view moduleIdLocation m of
-	CabalModule cabal _ _ -> cabal == c
+-- | Check if module in package-db
+inPackageDb :: PackageDb -> ModuleId -> Bool
+inPackageDb c m = case view moduleIdLocation m of
+	InstalledModule d _ _ -> d == c
 	_ -> False
 
+-- | Check if module in one of sandboxes
+inPackageDbStack :: PackageDbStack -> ModuleId -> Bool
+inPackageDbStack dbs m = case view moduleIdLocation m of
+	InstalledModule d _ _ -> d `elem` packageDbs dbs
+	_ -> False
+
 -- | Check if module in package
 inPackage :: String -> ModuleId -> Bool
 inPackage p m = case view moduleIdLocation m of
-	CabalModule _ package _ -> Just p == fmap (view packageName) package
+	InstalledModule _ package _ -> Just p == fmap (view packageName) package
 	_ -> False
 
 inVersion :: String -> ModuleId -> Bool
 inVersion v m = case view moduleIdLocation m of
-	CabalModule _ package _ -> Just v == fmap (view packageVersion) package
+	InstalledModule _ package _ -> Just v == fmap (view packageVersion) package
 	_ -> False
 
 -- | Check if module in file
@@ -96,9 +102,9 @@
 	_ -> False
 
 -- | Check if module got from cabal database
-byCabal :: ModuleId -> Bool
-byCabal m = case view moduleIdLocation m of
-	CabalModule _ _ _ -> True
+installed :: ModuleId -> Bool
+installed m = case view moduleIdLocation m of
+	InstalledModule _ _ _ -> True
 	_ -> False
 
 -- | Check if module is standalone
@@ -142,7 +148,7 @@
 	partition (isJust . fst) .
 	map ((mpackage . symbolModuleLocation) &&& id)
 	where
-		mpackage (CabalModule _ (Just p) _) = Just p
+		mpackage (InstalledModule _ (Just p) _) = Just p
 		mpackage _ = Nothing
 		pname = fmap (view packageName) . fst
 		pver = fmap (view packageVersion) . fst
@@ -159,22 +165,25 @@
 sourceModule proj ms = listToMaybe $ maybe (const []) (filter . (. view moduleId) . inProject) proj ms ++ filter (byFile . view moduleId) ms
 
 -- | Select module, visible in project or cabal
-visibleModule :: Cabal -> Maybe Project -> [Module] -> Maybe Module
-visibleModule cabal proj ms = listToMaybe $ maybe (const []) (filter . (. view moduleId) . inProject) proj ms ++ filter (inCabal cabal . view moduleId) ms
+-- TODO: PackageDbStack?
+visibleModule :: PackageDb -> Maybe Project -> [Module] -> Maybe Module
+visibleModule d proj ms = listToMaybe $ maybe (const []) (filter . (. view moduleId) . inProject) proj ms ++ filter (inPackageDb d . view moduleId) ms
 
 -- | Select preferred visible module
-preferredModule :: Cabal -> Maybe Project -> [ModuleId] -> Maybe ModuleId
-preferredModule cabal proj ms = listToMaybe $ concatMap (`filter` ms) order where
+-- TODO: PackageDbStack?
+preferredModule :: PackageDb -> Maybe Project -> [ModuleId] -> Maybe ModuleId
+preferredModule d proj ms = listToMaybe $ concatMap (`filter` ms) order where
 	order = [
 		maybe (const False) inProject proj,
 		byFile,
-		inCabal cabal,
+		inPackageDb d,
 		const True]
 
 -- | Remove duplicate modules, leave only `preferredModule`
-uniqueModules :: Cabal -> Maybe Project -> [ModuleId] -> [ModuleId]
-uniqueModules cabal proj =
-	mapMaybe (preferredModule cabal proj) .
+-- TODO: PackageDbStack?
+uniqueModules :: PackageDb -> Maybe Project -> [ModuleId] -> [ModuleId]
+uniqueModules d proj =
+	mapMaybe (preferredModule d proj) .
 	groupBy ((==) `on` view moduleIdName) .
 	sortBy (comparing (view moduleIdName))
 
diff --git a/src/HsDev/Tools/Ghc/Check.hs b/src/HsDev/Tools/Ghc/Check.hs
--- a/src/HsDev/Tools/Ghc/Check.hs
+++ b/src/HsDev/Tools/Ghc/Check.hs
@@ -6,7 +6,7 @@
 	Ghc,
 	module HsDev.Tools.Types,
 	module HsDev.Symbols.Types,
-	Cabal(..), Project(..),
+	PackageDb(..), PackageDbStack(..), Project(..),
 
 	recalcNotesTabs,
 
@@ -27,6 +27,8 @@
 import qualified ErrUtils as E
 
 import System.Directory.Paths
+import HsDev.PackageDb
+import HsDev.Scan.Browse (browsePackages)
 import HsDev.Symbols (moduleOpts)
 import HsDev.Symbols.Location
 import HsDev.Symbols.Types
@@ -35,35 +37,35 @@
 import HsDev.Util (readFileUtf8, ordNub)
 
 -- | Check files and collect warnings and errors
-checkFiles :: [String] -> Cabal -> [FilePath] -> Maybe Project -> Ghc [Note OutputMessage]
-checkFiles opts cabal files _ = do
+checkFiles :: [String] -> PackageDbStack -> [FilePath] -> Maybe Project -> Ghc [Note OutputMessage]
+checkFiles opts pdbs files _ = do
 	ch <- liftIO newChan
 	withFlags $ do
 		modifyFlags (\fs -> fs { log_action = logAction ch })
-		_ <- addCmdOpts ("-Wall" : (cabalOpt cabal ++ opts))
+		_ <- setCmdOpts ("-Wall" : (packageDbStackOpts pdbs ++ opts))
 		clearTargets
 		mapM (`makeTarget` Nothing) files >>= loadTargets
 	notes <- liftIO $ stopChan ch
 	liftIO $ recalcNotesTabs notes
 
 -- | Check module source
-check :: [String] -> Cabal -> Module -> Maybe String -> ExceptT String Ghc [Note OutputMessage]
-check opts cabal m msrc = case view moduleLocation m of
+check :: [String] -> PackageDbStack -> Module -> Maybe String -> ExceptT String Ghc [Note OutputMessage]
+check opts pdbs m msrc = case view moduleLocation m of
 	FileModule file proj -> do
 		ch <- liftIO newChan
-		pkgs <- lift listPackages
+		pkgs <- mapExceptT liftIO $ browsePackages opts pdbs
 		let
 			dir = fromMaybe
 				(sourceModuleRoot (view moduleName m) file) $
 				preview (_Just . projectPath) proj
 		dirExist <- liftIO $ doesDirectoryExist dir
 		lift $ withFlags $ (if dirExist then withCurrentDirectory dir else id) $ do
-			modifyFlags (\fs -> fs { log_action = logAction ch })
-			_ <- addCmdOpts $ concat [
+			_ <- setCmdOpts $ concat [
 				["-Wall"],
-				cabalOpt cabal,
+				packageDbStackOpts pdbs,
 				moduleOpts pkgs m,
 				opts]
+			modifyFlags (\fs -> fs { log_action = logAction ch })
 			clearTargets
 			target <- makeTarget (makeRelative dir file) msrc
 			loadTargets [target]
@@ -72,12 +74,12 @@
 	_ -> throwError "Module is not source"
 
 -- | Check module and collect warnings and errors
-checkFile :: [String] -> Cabal -> Module -> ExceptT String Ghc [Note OutputMessage]
-checkFile opts cabal m = check opts cabal m Nothing
+checkFile :: [String] -> PackageDbStack -> Module -> ExceptT String Ghc [Note OutputMessage]
+checkFile opts pdbs m = check opts pdbs m Nothing
 
 -- | Check module and collect warnings and errors
-checkSource :: [String] -> Cabal -> Module -> String -> ExceptT String Ghc [Note OutputMessage]
-checkSource opts cabal m src = check opts cabal m (Just src)
+checkSource :: [String] -> PackageDbStack -> Module -> String -> ExceptT String Ghc [Note OutputMessage]
+checkSource opts pdbs m src = check opts pdbs m (Just src)
 
 -- | Log  ghc warnings and errors as to chan
 -- You may have to apply recalcTabs on result notes
diff --git a/src/HsDev/Tools/Ghc/Types.hs b/src/HsDev/Tools/Ghc/Types.hs
--- a/src/HsDev/Tools/Ghc/Types.hs
+++ b/src/HsDev/Tools/Ghc/Types.hs
@@ -29,6 +29,8 @@
 import Pretty
 
 import System.Directory.Paths (canonicalize)
+import HsDev.Scan.Browse (browsePackages)
+import HsDev.PackageDb
 import HsDev.Symbols
 import HsDev.Tools.Ghc.Worker
 import HsDev.Tools.Types
@@ -96,20 +98,20 @@
 		v .:: "type"
 
 -- | Get all types in module
-fileTypes :: [String] -> Cabal -> Module -> Maybe String -> ExceptT String Ghc [Note TypedExpr]
-fileTypes opts cabal m msrc = case view moduleLocation m of
+fileTypes :: [String] -> PackageDbStack -> Module -> Maybe String -> ExceptT String Ghc [Note TypedExpr]
+fileTypes opts pdbs m msrc = case view moduleLocation m of
 	FileModule file proj -> do
 		file' <- liftIO $ canonicalize file
 		cts <- maybe (liftIO $ readFileUtf8 file') return msrc
-		pkgs <- lift listPackages
+		pkgs <- mapExceptT liftIO $ browsePackages opts pdbs
 		let
 			dir = fromMaybe
 				(sourceModuleRoot (view moduleName m) file') $
 				preview (_Just . projectPath) proj
 		dirExist <- liftIO $ doesDirectoryExist dir
 		lift $ withFlags $ (if dirExist then withCurrentDirectory dir else id) $ do
-			_ <- addCmdOpts $ concat [
-				cabalOpt cabal,
+			_ <- setCmdOpts $ concat [
+				packageDbStackOpts pdbs,
 				moduleOpts pkgs m,
 				opts]
 			target <- makeTarget (makeRelative dir file') msrc
@@ -142,5 +144,5 @@
 		return $ set (declaration . functionType) (Just $ fromString $ view (note . typedType) tnote) d
 
 -- | Infer types in module
-inferTypes :: [String] -> Cabal -> Module -> Maybe String -> ExceptT String Ghc Module
-inferTypes opts cabal m msrc = liftM (`setModuleTypes` m) $ fileTypes opts cabal m msrc
+inferTypes :: [String] -> PackageDbStack -> Module -> Maybe String -> ExceptT String Ghc Module
+inferTypes opts pdbs m msrc = liftM (`setModuleTypes` m) $ fileTypes opts pdbs m msrc
diff --git a/src/HsDev/Tools/Ghc/Worker.hs b/src/HsDev/Tools/Ghc/Worker.hs
--- a/src/HsDev/Tools/Ghc/Worker.hs
+++ b/src/HsDev/Tools/Ghc/Worker.hs
@@ -4,7 +4,8 @@
 	-- * Workers
 	ghcWorker, ghciWorker,
 	-- * Initializers and actions
-	withFlags, modifyFlags, addCmdOpts,
+	ghcRun,
+	withFlags, modifyFlags, addCmdOpts, setCmdOpts,
 	importModules, preludeModules,
 	evaluate,
 	clearTargets, makeTarget, loadTargets,
@@ -38,23 +39,27 @@
 -- | Ghc worker. Pass options and initializer action
 ghcWorker :: [String] -> Ghc () -> IO (Worker Ghc)
 ghcWorker opts initialize = startWorker (runGhc (Just libdir)) ghcInit id where
-	ghcInit f = do
-		fs <- getSessionDynFlags
-		defaultCleanupHandler fs $ do
-			(fs', _, _) <- parseDynamicFlags fs (map noLoc opts)
-			let fs'' = fs' {
-				ghcMode = CompManager,
-				ghcLink = LinkInMemory,
-				hscTarget = HscInterpreted }
-			_ <- setSessionDynFlags fs''
-			_ <- liftIO $ initPackages fs''
-			initialize
-			f
+	ghcInit f = ghcRun opts (initialize >> f)
 
 -- | Interpreter worker is worker with @preludeModules@ loaded
 ghciWorker :: IO (Worker Ghc)
 ghciWorker = ghcWorker [] (importModules preludeModules)
 
+-- | Run ghc
+ghcRun :: [String] -> Ghc a -> Ghc a
+ghcRun opts f = do
+	fs <- getSessionDynFlags
+	defaultCleanupHandler fs $ do
+		(fs', _, _) <- parseDynamicFlags fs (map noLoc opts)
+		let fs'' = fs' {
+			ghcMode = CompManager,
+			-- ghcLink = LinkInMemory,
+			-- hscTarget = HscInterpreted }
+			ghcLink = NoLink,
+			hscTarget = HscNothing }
+		void $ setSessionDynFlags fs''
+		f
+
 -- | Alter @DynFlags@ temporary
 withFlags :: Ghc a -> Ghc a
 withFlags = gbracket getSessionDynFlags (\fs -> setSessionDynFlags fs >> return ()) . const
@@ -69,13 +74,20 @@
 	_ <- liftIO $ initPackages fs'
 	return ()
 
-addCmdOpts :: [String] -> Ghc DynFlags
+-- | Add options without reinit session
+addCmdOpts :: [String] -> Ghc ()
 addCmdOpts opts = do
 	fs <- getSessionDynFlags
 	(fs', _, _) <- parseDynamicFlags fs (map noLoc opts)
-	_ <- setSessionDynFlags fs'
-	(fs'', _) <- liftIO $ initPackages fs'
-	return fs''
+	let fs'' = fs' {
+		ghcMode = CompManager,
+		ghcLink = NoLink,
+		hscTarget = HscNothing }
+	void $ setSessionDynFlags fs''
+
+-- | Set options after session reinit
+setCmdOpts :: [String] -> Ghc ()
+setCmdOpts opts = initGhcMonad (Just libdir) >> addCmdOpts opts
 
 -- | Import some modules
 importModules :: [String] -> Ghc ()
diff --git a/src/HsDev/Tools/GhcMod.hs b/src/HsDev/Tools/GhcMod.hs
--- a/src/HsDev/Tools/GhcMod.hs
+++ b/src/HsDev/Tools/GhcMod.hs
@@ -54,23 +54,26 @@
 import qualified Language.Haskell.GhcMod.Types as GhcMod
 
 import Control.Concurrent.Worker
-import HsDev.Cabal
+import HsDev.PackageDb
 import HsDev.Project
+import HsDev.Sandbox (searchPackageDbStack)
 import HsDev.Symbols
 import HsDev.Tools.Base
 import HsDev.Tools.Types
 import HsDev.Util ((.::), liftIOErrors, liftThrow, readFileUtf8, ordNub)
 
-list :: [String] -> Cabal -> ExceptT String IO [ModuleLocation]
-list opts cabal = runGhcMod (GhcMod.defaultOptions { GhcMod.optGhcUserOptions = opts }) $ do
+-- FIXME: Pass package-db stack options to ghc-mod
+list :: [String] -> PackageDbStack -> ExceptT String IO [ModuleLocation]
+list opts pdbs = runGhcMod (GhcMod.defaultOptions { GhcMod.optGhcUserOptions = opts }) $ do
 	ms <- (map splitPackage . lines) <$> GhcMod.modules True
-	return [CabalModule cabal (readMaybe p) m | (m, p) <- ms]
+	return [InstalledModule (topPackageDb pdbs) (readMaybe p) m | (m, p) <- ms]
 	where
 		splitPackage :: String -> (String, String)
 		splitPackage = second (drop 1) . break isSpace
 
-browse :: [String] -> Cabal -> String -> Maybe ModulePackage -> ExceptT String IO InspectedModule
-browse opts cabal mname mpackage = inspect thisLoc (return $ browseInspection opts) $ runGhcMod
+-- FIXME: Pass package-db stack options to ghc-mod
+browse :: [String] -> PackageDbStack -> String -> Maybe ModulePackage -> ExceptT String IO InspectedModule
+browse opts pdbs mname mpackage = inspect thisLoc (return $ browseInspection opts) $ runGhcMod
 	(GhcMod.defaultOptions { GhcMod.optGhcUserOptions = packageOpt mpackage ++ opts }) $ do
 		ds <- (mapMaybe parseDecl . lines) <$> GhcMod.browse
 			(GhcMod.defaultBrowseOpts {
@@ -89,7 +92,7 @@
 	where
 		mpkgname = maybe mname (\p -> view packageName p ++ ":" ++ mname) mpackage
 		thisLoc = view moduleIdLocation $ mloc mname
-		mloc mname' = ModuleId (fromString mname') $ CabalModule cabal Nothing mname'
+		mloc mname' = ModuleId (fromString mname') $ InstalledModule (topPackageDb pdbs) Nothing mname'
 		parseDecl s = do
 			groups <- matchRx rx s
 			let
@@ -117,10 +120,11 @@
 flags :: ExceptT String IO [String]
 flags = runGhcMod GhcMod.defaultOptions $ (lines . nullToNL) <$> GhcMod.flags
 
-info :: [String] -> Cabal -> FilePath -> String -> GhcModT IO Declaration
-info opts cabal file sname = do
+-- FIXME: Detect actual package-db for module
+info :: [String] -> PackageDbStack -> FilePath -> String -> GhcModT IO Declaration
+info opts pdbs file sname = do
 	fileCts <- liftIO $ readFileUtf8 file
-	rs <- withOptions (\o -> o { GhcMod.optGhcUserOptions = cabalOpt cabal ++ opts }) $
+	rs <- withOptions (\o -> o { GhcMod.optGhcUserOptions = packageDbStackOpts pdbs ++ opts }) $
 		liftM nullToNL $ GhcMod.info file (GhcMod.Expression sname)
 	toDecl fileCts rs
 	where
@@ -152,7 +156,7 @@
 		parsePos src = case splitRx ":(?=\\d)" src of
 			[_, line, column] ->  Position <$> readMaybe line <*> readMaybe column
 			_ -> Nothing
-		mkMod = CabalModule cabal Nothing
+		mkMod = InstalledModule (topPackageDb pdbs) Nothing
 		trim = p . p where
 			p = reverse . dropWhile isSpace
 
@@ -177,8 +181,8 @@
 		v .:: "expr" <*>
 		v .:: "type"
 
-typeOf :: [String] -> Cabal -> FilePath -> Int -> Int -> GhcModT IO [TypedRegion]
-typeOf opts cabal file line col = withOptions (\o -> o { GhcMod.optGhcUserOptions = cabalOpt cabal ++ opts }) $ do
+typeOf :: [String] -> PackageDbStack -> FilePath -> Int -> Int -> GhcModT IO [TypedRegion]
+typeOf opts pdbs file line col = withOptions (\o -> o { GhcMod.optGhcUserOptions = packageDbStackOpts pdbs ++ opts }) $ do
 	fileCts <- liftIO $ readFileUtf8 file
 	let
 		Position line' col' = calcTabs fileCts 8 (Position line col)
@@ -220,10 +224,10 @@
 	'\0' -> '\n'
 	ch -> ch
 
-check :: [String] -> Cabal -> [FilePath] -> Maybe Project -> GhcModT IO [Note OutputMessage]
-check opts cabal files _ = do
+check :: [String] -> PackageDbStack -> [FilePath] -> Maybe Project -> GhcModT IO [Note OutputMessage]
+check opts pdbs files _ = do
 	cts <- liftIO $ mapM readFileUtf8 files
-	withOptions (\o -> o { GhcMod.optGhcUserOptions = cabalOpt cabal ++ opts }) $ do
+	withOptions (\o -> o { GhcMod.optGhcUserOptions = packageDbStackOpts pdbs ++ opts }) $ do
 		res <- GhcMod.checkSyntax files
 		return $ map (recalcOutputMessageTabs (zip files cts)) $ parseOutputMessages res
 
@@ -252,16 +256,16 @@
 		GhcMod.withGhcModEnv cur opts $ \(env, _) ->
 			GhcMod.runGhcModT' env GhcMod.defaultGhcModState act
 
-locateGhcModEnv :: FilePath -> IO (Either Project Cabal)
+locateGhcModEnv :: FilePath -> IO (Either Project PackageDbStack)
 locateGhcModEnv f = do
 	mproj <- locateProject f
-	maybe (liftM Right $ getSandbox f) (return . Left) mproj
+	maybe (liftM Right $ searchPackageDbStack f) (return . Left) mproj
 
-ghcModEnvPath :: FilePath -> Either Project Cabal -> FilePath
-ghcModEnvPath defaultPath = either (view projectPath) (fromMaybe defaultPath . sandbox)
+ghcModEnvPath :: FilePath -> Either Project PackageDbStack -> FilePath
+ghcModEnvPath defaultPath = either (view projectPath) (fromMaybe defaultPath . preview packageDb . topPackageDb)
 
 -- | Create ghc-mod worker for project or for sandbox
-ghcModWorker :: Either Project Cabal -> IO (Worker (GhcModT IO))
+ghcModWorker :: Either Project PackageDbStack -> IO (Worker (GhcModT IO))
 ghcModWorker p = do
 	home <- getHomeDirectory
 	startWorker (runGhcModT'' $ ghcModEnvPath home p) id liftThrow
diff --git a/src/HsDev/Tools/GhcMod/InferType.hs b/src/HsDev/Tools/GhcMod/InferType.hs
--- a/src/HsDev/Tools/GhcMod/InferType.hs
+++ b/src/HsDev/Tools/GhcMod/InferType.hs
@@ -12,7 +12,7 @@
 import qualified Data.Text as T (unpack)
 import qualified Language.Haskell.GhcMod as GhcMod
 
-import HsDev.Cabal
+import HsDev.PackageDb
 import HsDev.Symbols
 import HsDev.Tools.GhcMod
 import HsDev.Util (withCurrentDirectory)
@@ -23,8 +23,8 @@
 untyped _ = False
 
 -- | Infer type of declaration
-inferType :: [String] -> Cabal -> FilePath -> Declaration -> GhcModT IO Declaration
-inferType opts cabal src decl'
+inferType :: [String] -> PackageDbStack -> FilePath -> Declaration -> GhcModT IO Declaration
+inferType opts pdbs src decl'
 	| untyped (view declaration decl') = doInfer
 	| otherwise = return decl'
 	where
@@ -32,23 +32,23 @@
 			inferred <- ((preview $ declaration . functionType . _Just) <$> byInfo) <|> (fmap fromString <$> byTypeOf)
 			return $ set (declaration . functionType) inferred decl'
 
-		byInfo = info opts cabal src (T.unpack $ view declarationName decl')
+		byInfo = info opts pdbs src (T.unpack $ view declarationName decl')
 		byTypeOf = case view declarationPosition decl' of
 			Nothing -> fail "No position"
-			Just (Position l c) -> (fmap typedType . listToMaybe) <$> typeOf opts cabal src l c
+			Just (Position l c) -> (fmap typedType . listToMaybe) <$> typeOf opts pdbs src l c
 
 -- | Infer types for module
-inferTypes :: [String] -> Cabal -> Module -> GhcModT IO Module
-inferTypes opts cabal m = case view moduleLocation m of
+inferTypes :: [String] -> PackageDbStack -> Module -> GhcModT IO Module
+inferTypes opts pdbs m = case view moduleLocation m of
 	FileModule src _ -> do
-		inferredDecls <- traverse (\d -> inferType opts cabal src d <|> return d) $
+		inferredDecls <- traverse (\d -> inferType opts pdbs src d <|> return d) $
 			view moduleDeclarations m
 		return $ set moduleDeclarations inferredDecls m
 	_ -> fail "Type infer works only for source files"
 
 -- | Infer type in module
-infer :: [String] -> Cabal -> Module -> ExceptT String IO Module
-infer opts cabal m = case view moduleLocation m of
+infer :: [String] -> PackageDbStack -> Module -> ExceptT String IO Module
+infer opts pdbs m = case view moduleLocation m of
 	FileModule src _ -> mapExceptT (withCurrentDirectory (sourceModuleRoot (view moduleName m) src)) $
-		runGhcMod GhcMod.defaultOptions $ inferTypes opts cabal m
+		runGhcMod GhcMod.defaultOptions $ inferTypes opts pdbs m
 	_ -> throwError "Type infer works only for source files"
diff --git a/src/HsDev/Tools/HDocs.hs b/src/HsDev/Tools/HDocs.hs
--- a/src/HsDev/Tools/HDocs.hs
+++ b/src/HsDev/Tools/HDocs.hs
@@ -37,12 +37,12 @@
 hdocs mloc opts = runExceptT (docs' mloc) >>= return . either (const M.empty) (force . HDocs.formatDocs) where
 	docs' :: ModuleLocation -> ExceptT String IO HDocs.ModuleDocMap
 	docs' (FileModule fpath _) = liftM snd $ HDocs.readSource opts fpath
-	docs' (CabalModule _ _ mname) = HDocs.moduleDocs opts mname
+	docs' (InstalledModule _ _ mname) = HDocs.moduleDocs opts mname
 	docs' _ = throwError $ "Can't get docs for: " ++ show mloc
 
 -- | Get all docs
-hdocsCabal :: Cabal -> [String] -> ExceptT String IO (Map String (Map String String))
-hdocsCabal cabal opts = liftM (M.map $ force . HDocs.formatDocs) $ HDocs.installedDocs (cabalOpt cabal ++ opts)
+hdocsCabal :: PackageDbStack -> [String] -> ExceptT String IO (Map String (Map String String))
+hdocsCabal pdbs opts = liftM (M.map $ force . HDocs.formatDocs) $ HDocs.installedDocs (packageDbStackOpts pdbs ++ opts)
 
 -- | Set docs for module
 setDocs :: Map String String -> Module -> Module
diff --git a/src/HsDev/Util.hs b/src/HsDev/Util.hs
--- a/src/HsDev/Util.hs
+++ b/src/HsDev/Util.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleContexts, OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts, OverloadedStrings, TemplateHaskell #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module HsDev.Util (
@@ -28,6 +28,8 @@
 	FromCmd(..),
 	cmdJson, withCmd, guardCmd,
 	withHelp, cmd, parseArgs,
+	-- * Version stuff
+	version, cutVersion, sameVersion, strVersion,
 
 	-- * Reexportss
 	module Control.Monad.Except,
@@ -36,6 +38,7 @@
 
 import Control.Arrow (second, left, (&&&))
 import Control.Exception
+import Control.Concurrent.Async
 import Control.Monad
 import Control.Monad.Except
 import qualified Control.Monad.Catch as C
@@ -43,7 +46,7 @@
 import Data.Aeson hiding (Result(..), Error)
 import qualified Data.Aeson.Types as A
 import Data.Char (isSpace)
-import Data.List (isPrefixOf, unfoldr)
+import Data.List (isPrefixOf, unfoldr, intercalate)
 import qualified Data.Map as M
 import Data.Maybe (catMaybes, fromMaybe)
 import qualified Data.Set as Set
@@ -59,13 +62,14 @@
 import System.FilePath
 import System.IO
 import qualified System.Log.Simple as Log
+import Text.Read (readMaybe)
 
-import Control.Concurrent.Async
+import HsDev.Version
 
 -- | Run action with current directory set
-withCurrentDirectory :: FilePath -> IO a -> IO a
-withCurrentDirectory cur act = bracket getCurrentDirectory setCurrentDirectory $
-	const (setCurrentDirectory cur >> act)
+withCurrentDirectory :: CatchIO.MonadCatchIO m => FilePath -> m a -> m a
+withCurrentDirectory cur act = CatchIO.bracket (liftIO getCurrentDirectory) (liftIO . setCurrentDirectory) $
+	const (liftIO (setCurrentDirectory cur) >> act)
 
 -- | Get directory contents safely
 directoryContents :: FilePath -> IO [FilePath]
@@ -288,3 +292,20 @@
 
 instance Log.MonadLog m => Log.MonadLog (ExceptT e m) where
 	askLog = lift Log.askLog
+
+-- | Get hsdev version as list of integers
+version :: Maybe [Int]
+version = mapM readMaybe $ split (== '.') $cabalVersion
+
+-- | Cut version to contain only significant numbers (currently 3)
+cutVersion :: Maybe [Int] -> Maybe [Int]
+cutVersion = fmap (take 3)
+
+-- | Check if version is the same
+sameVersion :: Maybe [Int] -> Maybe [Int] -> Bool
+sameVersion l r = fromMaybe False $ liftA2 (==) l r
+
+-- | Version to string
+strVersion :: Maybe [Int] -> String
+strVersion Nothing = "unknown"
+strVersion (Just vers) = intercalate "." $ map show vers
diff --git a/src/HsDev/Watcher.hs b/src/HsDev/Watcher.hs
--- a/src/HsDev/Watcher.hs
+++ b/src/HsDev/Watcher.hs
@@ -1,6 +1,6 @@
 module HsDev.Watcher (
-	watchProject, watchModule, watchSandbox,
-	unwatchProject, unwatchModule, unwatchSandbox,
+	watchProject, watchModule, watchPackageDb, watchPackageDbStack,
+	unwatchProject, unwatchModule, unwatchPackageDb,
 	isSource, isCabal, isConf,
 
 	module System.Directory.Watcher,
@@ -29,14 +29,19 @@
 watchModule :: Watcher -> ModuleLocation -> IO ()
 watchModule w (FileModule f Nothing) = watchDir w (takeDirectory f) isSource WatchedModule
 watchModule w (FileModule _ (Just proj)) = watchProject w proj []
-watchModule w (CabalModule cabal _ _) = watchSandbox w cabal []
 watchModule _ _ = return ()
 
--- | Watch for sandbox
-watchSandbox :: Watcher -> Cabal -> [String] -> IO ()
-watchSandbox _ Cabal _ = return ()
-watchSandbox w (Sandbox f) opts = watchTree w f isConf (WatchedSandbox (Sandbox f) opts)
+-- | Watch for top of package-db stack
+watchPackageDb :: Watcher -> PackageDbStack -> [String] -> IO ()
+watchPackageDb w pdbs opts = case topPackageDb pdbs of
+	GlobalDb -> return () -- TODO: Watch for global package-db
+	UserDb -> return () -- TODO: Watch for user package-db
+	(PackageDb pdb) -> watchTree w pdb isConf (WatchedPackageDb pdbs opts)
 
+-- | Watch for package-db stack
+watchPackageDbStack :: Watcher -> PackageDbStack -> [String] -> IO ()
+watchPackageDbStack w pdbs opts = mapM_ (\pdbs' -> watchPackageDb w pdbs' opts) $ packageDbStacks pdbs
+
 unwatchProject :: Watcher -> Project -> IO ()
 unwatchProject w proj = do
 	mapM_ (unwatchTree w) dirs
@@ -48,12 +53,14 @@
 unwatchModule :: Watcher -> ModuleLocation -> IO ()
 unwatchModule w (FileModule f Nothing) = void $ unwatchDir w (takeDirectory f)
 unwatchModule _ (FileModule _ (Just _)) = return ()
-unwatchModule _ (CabalModule _ _ _) = return ()
+unwatchModule _ (InstalledModule _ _ _) = return ()
 unwatchModule _ _ = return ()
 
-unwatchSandbox :: Watcher -> Cabal -> IO ()
-unwatchSandbox _ Cabal = return ()
-unwatchSandbox w (Sandbox f) = void $ unwatchTree w f
+-- | Unwatch package-db
+unwatchPackageDb :: Watcher -> PackageDb -> IO ()
+unwatchPackageDb _ GlobalDb = return () -- TODO: Unwatch global package-db
+unwatchPackageDb _ UserDb = return () -- TODO: Unwatch user package-db
+unwatchPackageDb w (PackageDb pdb) = void $ unwatchTree w pdb
 
 isSource :: Event -> Bool
 isSource (Event _ f _) = takeExtension f == ".hs"
diff --git a/src/HsDev/Watcher/Types.hs b/src/HsDev/Watcher/Types.hs
--- a/src/HsDev/Watcher/Types.hs
+++ b/src/HsDev/Watcher/Types.hs
@@ -2,13 +2,13 @@
 	Watched(..),
 	Watcher,
 
-	Cabal, Project
+	PackageDbStack, Project
 	) where
 
 import qualified System.Directory.Watcher as W
 import HsDev.Project (Project)
-import HsDev.Cabal (Cabal)
+import HsDev.PackageDb (PackageDbStack)
 
-data Watched = WatchedProject Project [String] | WatchedSandbox Cabal [String] | WatchedModule
+data Watched = WatchedProject Project [String] | WatchedPackageDb PackageDbStack [String] | WatchedModule
 
 type Watcher = W.Watcher Watched
diff --git a/tools/hsinspect.hs b/tools/hsinspect.hs
--- a/tools/hsinspect.hs
+++ b/tools/hsinspect.hs
@@ -6,15 +6,18 @@
 
 import Control.Monad (liftM, (>=>))
 import Control.Monad.IO.Class
+import Control.Monad.Except (ExceptT(..), runExceptT)
 import Data.Aeson (toJSON)
 import System.Directory (canonicalizePath)
 import System.FilePath (takeExtension)
 
+import HsDev.PackageDb
 import HsDev.Project (readProject)
 import HsDev.Scan (scanModule, scanModify)
 import HsDev.Inspect (inspectContents, inspectDocs, getDefines)
-import HsDev.Symbols.Location (ModuleLocation(..), Cabal(..))
-import HsDev.Tools.GhcMod.InferType (infer)
+import HsDev.Symbols.Location (ModuleLocation(..))
+import HsDev.Tools.Ghc.Types (inferTypes)
+import HsDev.Tools.Ghc.Worker
 
 import Tool
 
@@ -35,12 +38,13 @@
 		fname' <- liftIO $ canonicalizePath fname
 		defs <- liftIO getDefines
 		im <- scanModule defs ghcs (FileModule fname' Nothing) Nothing
+		ghc <- liftIO $ ghcWorker ghcs (return ())
 		let
 			scanAdditional =
 				scanModify (\opts' _ -> inspectDocs opts') >=>
-				scanModify infer
+				scanModify (\opts' pdbs m -> ExceptT (inWorker ghc (runExceptT $ inferTypes opts' pdbs m Nothing)))
 		toJSON <$> scanAdditional im
 	inspect' (Opts (Just fcabal@(takeExtension -> ".cabal")) _) = do
 		fcabal' <- liftIO $ canonicalizePath fcabal
 		toJSON <$> readProject fcabal'
-	inspect' (Opts (Just mname) ghcs) = toJSON <$> scanModule [] ghcs (CabalModule Cabal Nothing mname) Nothing
+	inspect' (Opts (Just mname) ghcs) = toJSON <$> scanModule [] ghcs (InstalledModule UserDb Nothing mname) Nothing
