diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -9,6 +9,12 @@
     <img src="https://niv.nmattia.com/niv.svg">
 </p>
 
+
+* [Install](#install)
+* [Build](#build)
+* [Usage](#usage)
+* [FAQ](#frequently-asked-questions)
+
 ## Install
 
 `niv` is available in [`nixpkgs`](https://github.com/NixOS/nixpkgs) on the
@@ -16,7 +22,9 @@
 `haskellPackages.niv`. Otherwise, run:
 
 ``` bash
-$ nix-env -iA niv -f https://github.com/nmattia/niv/tarball/master
+$ nix-env -iA niv -f https://github.com/nmattia/niv/tarball/master \
+    --substituters https://niv.cachix.org \
+    --trusted-public-keys niv.cachix.org-1:X32PCg2e/zAm3/uD1ScqW2z/K0LtDyNV7RdaxIuLgQM=
 ```
 
 ## Build
@@ -99,13 +107,13 @@
 ``` json
 {
     "nixpkgs": {
-        "url": "https://github.com/NixOS/nixpkgs-channels/archive/109a28ab954a0ad129f7621d468f829981b8b96c.tar.gz",
+        "url": "https://github.com/NixOS/nixpkgs/archive/109a28ab954a0ad129f7621d468f829981b8b96c.tar.gz",
         "owner": "NixOS",
         "branch": "nixos-19.09",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
-        "repo": "nixpkgs-channels",
+        "repo": "nixpkgs",
         "sha256": "12wnxla7ld4cgpdndaipdh3j4zdalifk287ihxhnmrzrghjahs3q",
-        "description": "Nixpkgs/NixOS branches that track the Nixpkgs/NixOS channels",
+        "description": "Nix Packages collection",
         "rev": "109a28ab954a0ad129f7621d468f829981b8b96c"
     },
     "niv": {
@@ -204,7 +212,7 @@
 ```
 niv - dependency manager for Nix projects
 
-version: 0.2.13
+version: 0.2.14
 
 Usage: niv [-s|--sources-file FILE] COMMAND
 
@@ -221,7 +229,6 @@
   modify                   Modify dependency attributes without performing an
                            update
   drop                     Drop dependency
-
 ```
 
 #### Add
@@ -230,7 +237,7 @@
 Examples:
 
   niv add stedolan/jq
-  niv add NixOS/nixpkgs-channels -n nixpkgs -b nixos-19.09
+  niv add NixOS/nixpkgs -n nixpkgs -b nixpkgs-unstable
   niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip
 
 Usage: niv add PACKAGE [-n|--name NAME] ([-a|--attribute KEY=VAL] |
@@ -259,7 +266,7 @@
 Experimental commands:
   git                      Add a git dependency. Experimental.
   github                   Add a GitHub dependency
-
+  local                    Add a local dependency. Experimental.
 ```
 
 #### Update
@@ -292,7 +299,6 @@
                            'file' or 'tarball'. If not set, the value is
                            inferred from the suffix of the URL.
   -h,--help                Show this help text
-
 ```
 
 #### Modify
@@ -325,7 +331,6 @@
                            'file' or 'tarball'. If not set, the value is
                            inferred from the suffix of the URL.
   -h,--help                Show this help text
-
 ```
 
 #### Drop
@@ -341,18 +346,21 @@
 
 Available options:
   -h,--help                Show this help text
-
 ```
 
 #### Init
 
 ```
-Usage: niv init 
+Usage: niv init ([--no-nixpkgs] | [-b|--nixpkgs-branch ARG]
+                [--nixpkgs OWNER/REPO])
   Initialize a Nix project. Existing files won't be modified.
 
 Available options:
+  --no-nixpkgs             Don't add a nixpkgs entry to sources.json.
+  -b,--nixpkgs-branch ARG  The nixpkgs branch to use. (default: "release-20.03")
+  --nixpkgs OWNER/REPO     Use a custom nixpkgs repository from
+                           GitHub. (default: NixOS/nixpkgs)
   -h,--help                Show this help text
-
 ```
 
 #### show
@@ -362,9 +370,46 @@
 
 Available options:
   -h,--help                Show this help text
-
 ```
 
 [Nix]: https://nixos.org/nix/
 [jq]: https://stedolan.github.io/jq/
 [GHC]: https://www.haskell.org/ghc/
+
+
+## Frequently Asked Questions
+
+### Can you use private GitHub repositories?
+
+Yes. There are two ways:
+
+#### 1. Use the git protocol
+
+When using the git protocol, your public SSH keypair is used to authenticate
+you:
+
+``` shell
+$ niv add git git@github.com:my_user/my_private_repo
+```
+
+##### 2. Use the netrc file
+
+in order to `niv add` a private github repo you'll need to:
+
+1. create a .netrc file with the following content
+```
+machine github.com
+  login YOUR_GITHUB_USER_NAME
+  password YOUR_GITHUB_TOKEN
+```
+
+2. add the path to the above file to `/etc/nix/nix.conf`:
+```
+netrc-file = /PATH/TO/.netrc
+```
+
+3. set `GITHUB_TOKEN` env var when calling `niv add`
+```
+GITHUB_TOKEN=$YOUR_GITHUB_TOKEN niv add ...
+```
+
diff --git a/niv.cabal b/niv.cabal
--- a/niv.cabal
+++ b/niv.cabal
@@ -1,13 +1,13 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.32.0.
+-- This file has been generated from package.yaml by hpack version 0.33.0.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: a1d6256f329a5a130dcb0d8cbcbef0144451cc06f2ac5e70034bf3ed419b8914
+-- hash: 7f73602ea1ac16df6a54a599572573246b2d3260596b88111bc2971a028ac645
 
 name:           niv
-version:        0.2.13
+version:        0.2.14
 synopsis:       Easy dependency management for Nix projects
 description:    Easy dependency management for Nix projects.
 category:       Development
@@ -41,6 +41,7 @@
       Niv.GitHub.API
       Niv.GitHub.Cmd
       Niv.GitHub.Test
+      Niv.Local.Cmd
       Niv.Logger
       Niv.Sources
       Niv.Sources.Test
diff --git a/nix/sources.nix b/nix/sources.nix
--- a/nix/sources.nix
+++ b/nix/sources.nix
@@ -12,36 +12,29 @@
     else
       pkgs.fetchurl { inherit (spec) url sha256; };
 
-  fetch_tarball = pkgs: spec:
-    if spec.builtin or true then
-      builtins_fetchTarball { inherit (spec) url sha256; }
-    else
-      pkgs.fetchzip { inherit (spec) url sha256; };
+  fetch_tarball = pkgs: name: spec:
+    let
+      ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str);
+      # sanitize the name, though nix will still fail if name starts with period
+      name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src";
+    in
+      if spec.builtin or true then
+        builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
+      else
+        pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
 
   fetch_git = spec:
     builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
 
-  fetch_builtin-tarball = spec:
-    builtins.trace
-      ''
-        WARNING:
-          The niv type "builtin-tarball" will soon be deprecated. You should
-          instead use `builtin = true`.
-
-          $ niv modify <package> -a type=tarball -a builtin=true
-      ''
-      builtins_fetchTarball { inherit (spec) url sha256; };
+  fetch_local = spec: spec.path;
 
-  fetch_builtin-url = spec:
-    builtins.trace
-      ''
-        WARNING:
-          The niv type "builtin-url" will soon be deprecated. You should
-          instead use `builtin = true`.
+  fetch_builtin-tarball = name: throw
+    ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
+        $ niv modify ${name} -a type=tarball -a builtin=true'';
 
-          $ niv modify <package> -a type=file -a builtin=true
-      ''
-      (builtins_fetchurl { inherit (spec) url sha256; });
+  fetch_builtin-url = name: throw
+    ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
+        $ niv modify ${name} -a type=file -a builtin=true'';
 
   #
   # Various helpers
@@ -72,10 +65,11 @@
     if ! builtins.hasAttr "type" spec then
       abort "ERROR: niv spec ${name} does not have a 'type' attribute"
     else if spec.type == "file" then fetch_file pkgs spec
-    else if spec.type == "tarball" then fetch_tarball pkgs spec
+    else if spec.type == "tarball" then fetch_tarball pkgs name spec
     else if spec.type == "git" then fetch_git spec
-    else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec
-    else if spec.type == "builtin-url" then fetch_builtin-url spec
+    else if spec.type == "local" then fetch_local spec
+    else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
+    else if spec.type == "builtin-url" then fetch_builtin-url name
     else
       abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
 
@@ -87,13 +81,23 @@
     listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
   );
 
+  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
+  range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
+
+  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
+  stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
+
+  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
+  stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
+  concatStrings = builtins.concatStringsSep "";
+
   # fetchTarball version that is compatible between all the versions of Nix
-  builtins_fetchTarball = { url, sha256 }@attrs:
+  builtins_fetchTarball = { url, name, sha256 }@attrs:
     let
       inherit (builtins) lessThan nixVersion fetchTarball;
     in
       if lessThan nixVersion "1.12" then
-        fetchTarball { inherit url; }
+        fetchTarball { inherit name url; }
       else
         fetchTarball attrs;
 
diff --git a/src/Niv/Cli.hs b/src/Niv/Cli.hs
--- a/src/Niv/Cli.hs
+++ b/src/Niv/Cli.hs
@@ -19,6 +19,7 @@
 import Data.Version (showVersion)
 import Niv.Cmd
 import Niv.Git.Cmd
+import Niv.Local.Cmd
 import Niv.GitHub.Cmd
 import Niv.Logger
 import Niv.Sources
@@ -96,17 +97,59 @@
 -- INIT
 -------------------------------------------------------------------------------
 
+-- | Whether or not to fetch nixpkgs
+data FetchNixpkgs
+  = NoNixpkgs
+  | YesNixpkgs T.Text Nixpkgs -- branch, nixpkgs
+
+data Nixpkgs = Nixpkgs T.Text T.Text -- owner, repo
+
+instance Show Nixpkgs where
+  show (Nixpkgs o r) = T.unpack o <> "/" <> T.unpack r
+
+-- | The default nixpkgs
+defaultNixpkgsRepo, defaultNixpkgsUser, defaultNixpkgsBranch :: T.Text
+defaultNixpkgsRepo = "nixpkgs"
+defaultNixpkgsUser = "NixOS"
+defaultNixpkgsBranch = "release-20.03"
+
 parseCmdInit :: Opts.ParserInfo (NIO ())
-parseCmdInit = Opts.info (pure cmdInit <**> Opts.helper) $ mconcat desc
+parseCmdInit = Opts.info (cmdInit <$> parseNixpkgs <**> Opts.helper) $ mconcat desc
   where
+    customNixpkgsReader = Opts.maybeReader $ \(T.pack -> repo) -> case T.splitOn "/" repo of
+      [owner, reponame] -> Just (Nixpkgs owner reponame)
+      _ -> Nothing
+    parseNixpkgs =
+      Opts.flag' NoNixpkgs
+        (
+          Opts.long "no-nixpkgs" <>
+          Opts.help "Don't add a nixpkgs entry to sources.json."
+        ) <|>
+      (YesNixpkgs <$>
+        (Opts.strOption
+        (
+          Opts.long "nixpkgs-branch" <>
+          Opts.short 'b' <>
+          Opts.help "The nixpkgs branch to use." <>
+          Opts.showDefault <>
+          Opts.value defaultNixpkgsBranch
+        )
+      ) <*> Opts.option customNixpkgsReader
+      (
+        Opts.long "nixpkgs" <>
+        Opts.showDefault <>
+        Opts.help "Use a custom nixpkgs repository from GitHub." <>
+        Opts.metavar "OWNER/REPO" <>
+        Opts.value (Nixpkgs defaultNixpkgsUser defaultNixpkgsRepo)
+      ))
     desc =
       [ Opts.fullDesc
       , Opts.progDesc
           "Initialize a Nix project. Existing files won't be modified."
       ]
 
-cmdInit :: NIO ()
-cmdInit = do
+cmdInit :: FetchNixpkgs -> NIO ()
+cmdInit nixpkgs = do
     job "Initializing" $ do
       fsj <- getFindSourcesJson
 
@@ -125,7 +168,7 @@
         , ( pathNixSourcesJson fsj
           , \path -> do
               createFile path initNixSourcesJsonContent
-              -- Imports @niv@ and @nixpkgs@ (19.09)
+              -- Imports @niv@ and @nixpkgs@
               say "Importing 'niv' ..."
               cmdAdd (updateCmd githubCmd) (PackageName "niv")
                 (specToFreeAttrs $ PackageSpec $ HMS.fromList
@@ -133,14 +176,19 @@
                   , "repo" .= ("niv" :: T.Text)
                   ]
                 )
-              say "Importing 'nixpkgs' ..."
-              cmdAdd (updateCmd githubCmd) (PackageName "nixpkgs")
-                (specToFreeAttrs $ PackageSpec $ HMS.fromList
-                  [ "owner" .= ("NixOS" :: T.Text)
-                  , "repo" .= ("nixpkgs-channels" :: T.Text)
-                  , "branch" .= ("nixos-19.09" :: T.Text)
-                  ]
-                )
+              case nixpkgs of
+                NoNixpkgs -> say "Not importing 'nixpkgs'."
+                YesNixpkgs branch nixpkgs' -> do
+                  say "Importing 'nixpkgs' ..."
+                  let (owner, repo) =  case nixpkgs' of
+                        Nixpkgs o r -> (o,r)
+                  cmdAdd (updateCmd githubCmd) (PackageName "nixpkgs")
+                    (specToFreeAttrs $ PackageSpec $ HMS.fromList
+                      [ "owner" .= owner
+                      , "repo" .= repo
+                      , "branch" .= branch
+                      ]
+                    )
           , \path _content -> dontCreateFile path)
         ] $ \(path, onCreate, onUpdate) -> do
             exists <- li $ Dir.doesFileExist path
@@ -190,13 +238,16 @@
     parseCmd cmd = uncurry (cmdAdd (updateCmd cmd)) <$> (parseCmdArgs cmd)
     parseCmdAddGit =
       Opts.info (parseCmd gitCmd <**> Opts.helper) (description gitCmd)
+    parseCmdAddLocal =
+      Opts.info (parseCmd localCmd <**> Opts.helper) (description localCmd)
     parseCmdAddGitHub =
       Opts.info (parseCmd githubCmd <**> Opts.helper) (description githubCmd)
     parseCommands = Opts.subparser
         ( Opts.hidden <>
           Opts.commandGroup "Experimental commands:" <>
           Opts.command "git" parseCmdAddGit <>
-          Opts.command "github" parseCmdAddGitHub
+          Opts.command "github" parseCmdAddGitHub <>
+          Opts.command "local" parseCmdAddLocal
         )
 
 -- | only used in shortcuts (niv add foo/bar ...) because PACKAGE is NOT
@@ -341,6 +392,7 @@
             -- github
             let cmd = case HMS.lookup "type" (unPackageSpec defaultSpec) of
                   Just "git" -> gitCmd
+                  Just "local" -> localCmd
                   _ -> githubCmd
             fmap attrsToSpec <$> li (tryEvalUpdate
               (specToLockedAttrs cliSpec <> specToFreeAttrs defaultSpec)
@@ -366,6 +418,7 @@
           -- github
           let cmd = case HMS.lookup "type" (unPackageSpec defaultSpec) of
                 Just "git" -> gitCmd
+                Just "local" -> localCmd
                 _ -> githubCmd
           finalSpec <- fmap attrsToSpec <$> li (tryEvalUpdate
             initialSpec
diff --git a/src/Niv/GitHub.hs b/src/Niv/GitHub.hs
--- a/src/Niv/GitHub.hs
+++ b/src/Niv/GitHub.hs
@@ -33,7 +33,7 @@
       (useOrSet "url_template" <<< completeSpec) <+> (load "url_template") -<
       ()
     url <- update "url" -< urlTemplate
-    let isTar = ("tar.gz" `T.isSuffixOf`) <$> url
+    let isTar = (\u -> "tar.gz" `T.isSuffixOf` u || ".tgz" `T.isSuffixOf` u) <$> url
     useOrSet "type" -< bool "file" "tarball" <$> isTar :: Box T.Text
     let doUnpack = isTar
     _sha256 <- update "sha256" <<< run (\(up, u) -> prefetch up u) -< (,) <$> doUnpack <*> url
diff --git a/src/Niv/GitHub/Cmd.hs b/src/Niv/GitHub/Cmd.hs
--- a/src/Niv/GitHub/Cmd.hs
+++ b/src/Niv/GitHub/Cmd.hs
@@ -110,7 +110,7 @@
       "Examples:" Opts.<$$>
       "" Opts.<$$>
       "  niv add stedolan/jq" Opts.<$$>
-      "  niv add NixOS/nixpkgs-channels -n nixpkgs -b nixos-19.09" Opts.<$$>
+      "  niv add NixOS/nixpkgs -n nixpkgs -b nixpkgs-unstable" Opts.<$$>
       "  niv add my-package -v alpha-0.1 -t http://example.com/archive/<version>.zip"
   ]
 
diff --git a/src/Niv/Local/Cmd.hs b/src/Niv/Local/Cmd.hs
new file mode 100644
--- /dev/null
+++ b/src/Niv/Local/Cmd.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
+
+module Niv.Local.Cmd where
+
+import Niv.Cmd
+import Control.Arrow
+import Niv.Sources
+import Niv.Update
+import qualified Data.Aeson as Aeson
+import qualified Data.HashMap.Strict as HMS
+import qualified Data.Text as T
+import qualified Options.Applicative as Opts
+import qualified Options.Applicative.Help.Pretty as Opts
+
+localCmd :: Cmd
+localCmd = Cmd
+  { description = describeLocal
+  , parseCmdShortcut = parseLocalShortcut
+  , parsePackageSpec = parseLocalPackageSpec
+  , updateCmd = proc () -> do
+      useOrSet "type" -< ("local" :: Box T.Text)
+      returnA -< ()
+  , name = "local"
+  }
+
+parseLocalShortcut :: T.Text -> Maybe (PackageName, Aeson.Object)
+parseLocalShortcut txt =
+    if (T.isPrefixOf "./" txt || T.isPrefixOf "/" txt ) then do
+      let n = last $ T.splitOn "/" txt
+      Just (PackageName n, HMS.fromList [ ("path", Aeson.String txt) ])
+    else Nothing
+
+parseLocalPackageSpec :: Opts.Parser PackageSpec
+parseLocalPackageSpec = PackageSpec . HMS.fromList <$> parseParams
+  where
+    parseParams :: Opts.Parser [(T.Text, Aeson.Value)]
+    parseParams = maybe [] pure <$> Opts.optional parsePath
+
+    parsePath =
+      ("path", ) . Aeson.String <$> Opts.strOption
+        ( Opts.long "path" <>
+          Opts.metavar "PATH"
+        )
+
+describeLocal :: Opts.InfoMod a
+describeLocal = mconcat
+  [ Opts.fullDesc
+  , Opts.progDesc "Add a local dependency. Experimental."
+  , Opts.headerDoc $ Just $
+      "Examples:" Opts.<$$>
+      "" Opts.<$$>
+      "  niv add local ./foo/bar"
+  ]
diff --git a/src/Niv/Sources.hs b/src/Niv/Sources.hs
--- a/src/Niv/Sources.hs
+++ b/src/Niv/Sources.hs
@@ -147,6 +147,10 @@
   | V14
   | V15
   | V16
+  | V17
+  -- prettify derivation name
+  -- add 'local' type of sources
+  | V18
   deriving stock (Bounded, Enum, Eq)
 
 -- | A user friendly version
@@ -168,6 +172,8 @@
     V14 -> "14"
     V15 -> "15"
     V16 -> "16"
+    V17 -> "17"
+    V18 -> "18"
 
 latestVersionMD5 :: T.Text
 latestVersionMD5 = sourcesVersionToMD5 maxBound
@@ -196,6 +202,8 @@
     V14 -> "b470e235e7bcbf106d243fea90b6cfc9"
     V15 -> "dc11af910773ec9b4e505e0f49ebcfd2"
     V16 -> "2d93c52cab8e960e767a79af05ca572a"
+    V17 -> "149b8907f7b08dc1c28164dfa55c7fad"
+    V18 -> "bc5e6aefcaa6f9e0b2155ca4f44e5a33"
 
 -- | The MD5 sum of ./nix/sources.nix
 sourcesNixMD5 :: IO T.Text
