diff --git a/cmd/delete.go b/cmd/delete.go
index f7df57efdbd4e7c86d23d045ef5d3359c0d6d360..5ebe5ba30d0cee04b0e713a04264e6b9d959bd2c 100644
--- a/cmd/delete.go
+++ b/cmd/delete.go
@@ -55,7 +55,7 @@ var deleteCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := readObjs(cmd, args)
+		objs, err := expandEnvCmdObjs(cmd, args)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/diff.go b/cmd/diff.go
index 22664a2215d192de30e6fd926a1b180f0df2828a..887631a0ce73267dfc30938167bbfb9bce420353 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -53,7 +53,7 @@ var diffCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := readObjs(cmd, args)
+		objs, err := expandEnvCmdObjs(cmd, args)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/root.go b/cmd/root.go
index 1b836b76ebf0dae49a7f89bb33ad521e5af5a8c0..7f24777cd2cf1210d8f48bacf7e8104addf5d6f1 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -35,7 +35,6 @@ import (
 	"k8s.io/client-go/tools/clientcmd"
 
 	"github.com/ksonnet/kubecfg/metadata"
-	"github.com/ksonnet/kubecfg/pkg/kubecfg"
 	"github.com/ksonnet/kubecfg/template"
 	"github.com/ksonnet/kubecfg/utils"
 
@@ -245,10 +244,14 @@ func restClientPool(cmd *cobra.Command) (dynamic.ClientPool, discovery.Discovery
 	return pool, discoCache, nil
 }
 
+// addEnvCmdFlags adds the flags that are common to the family of commands
+// whose form is `[<env>|-f <file-name>]`, e.g., `update` and `delete`.
 func addEnvCmdFlags(cmd *cobra.Command) {
 	cmd.PersistentFlags().StringArrayP(flagFile, flagFileShort, nil, "Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)")
 }
 
+// parseEnvCmd parses the family of commands that come in the form `[<env>|-f
+// <file-name>]`, e.g., `update` and `delete`.
 func parseEnvCmd(cmd *cobra.Command, args []string) (*string, []string, error) {
 	flags := cmd.Flags()
 
@@ -265,8 +268,13 @@ func parseEnvCmd(cmd *cobra.Command, args []string) (*string, []string, error) {
 	return env, files, nil
 }
 
-func readObjs(cmd *cobra.Command, args []string) ([]*unstructured.Unstructured, error) {
-	env, f, err := parseEnvCmd(cmd, args)
+// expandEnvCmdObjs finds and expands templates for the family of commands of
+// the form `[<env>|-f <file-name>]`, e.g., `update` and `delete`. That is, if
+// the user passes a list of files, we will expand all templates in those files,
+// while if a user passes an environment name, we will expand all component
+// files using that environment.
+func expandEnvCmdObjs(cmd *cobra.Command, args []string) ([]*unstructured.Unstructured, error) {
+	env, fileNames, err := parseEnvCmd(cmd, args)
 	if err != nil {
 		return nil, err
 	}
@@ -281,10 +289,40 @@ func readObjs(cmd *cobra.Command, args []string) ([]*unstructured.Unstructured,
 		return nil, err
 	}
 
-	files, err := kubecfg.GetFiles(metadata.AbsPath(cwd), env, f)
-	if err != nil {
-		return nil, err
+	//
+	// Get all filenames that contain templates to expand. Importantly, we need to
+	// enforce the form `[<env-name>|-f <file-name>]`; that is, we need to make
+	// sure that the user either passed an environment name or a `-f` flag.
+	//
+
+	envPresent := env != nil
+	filesPresent := len(fileNames) > 0
+
+	// This is equivalent to: `if !xor(envPresent, filesPresent) {`
+	if envPresent && filesPresent {
+		return nil, fmt.Errorf("Either an environment name or a file list is required, but not both")
+	} else if !envPresent && !filesPresent {
+		return nil, fmt.Errorf("Must specify either an environment or a file list")
 	}
 
-	return expander.Expand(files)
+	if envPresent {
+		manager, err := metadata.Find(metadata.AbsPath(cwd))
+		if err != nil {
+			return nil, err
+		}
+
+		libPath, vendorLibPath := manager.LibPaths()
+		expander.FlagJpath = append([]string{string(libPath), string(vendorLibPath)}, expander.FlagJpath...)
+
+		fileNames, err = manager.ComponentPaths()
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	//
+	// Expand templates.
+	//
+
+	return expander.Expand(fileNames)
 }
diff --git a/cmd/show.go b/cmd/show.go
index 5ea288e549043adc1e299f3ca29f21ae32fa4259..9e4ac5c53d173ad4d0760667cfc9dec87f88262c 100644
--- a/cmd/show.go
+++ b/cmd/show.go
@@ -45,7 +45,7 @@ var showCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := readObjs(cmd, args)
+		objs, err := expandEnvCmdObjs(cmd, args)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/update.go b/cmd/update.go
index 41b104bde18b4c8741c2a73fe7cbc536298bbafe..8f0e72120a7b8eb8b9748de24d03256a11fb1385 100644
--- a/cmd/update.go
+++ b/cmd/update.go
@@ -101,7 +101,7 @@ local configuration. Accepts JSON, YAML, or Jsonnet.`,
 			return err
 		}
 
-		objs, err := readObjs(cmd, args)
+		objs, err := expandEnvCmdObjs(cmd, args)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/validate.go b/cmd/validate.go
index 171c1e3d50376b23c887d7c05cb3ca1a0b5cf0b3..f05f75e95ec3917bd5fbd1d4a48245f6454348ee 100644
--- a/cmd/validate.go
+++ b/cmd/validate.go
@@ -39,7 +39,7 @@ var validateCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := readObjs(cmd, args)
+		objs, err := expandEnvCmdObjs(cmd, args)
 		if err != nil {
 			return err
 		}
diff --git a/metadata/interface.go b/metadata/interface.go
index bc58d16ba114ffbfb78da45f94ba63046a38a5ed..5c81943b69a4432399f4241d8698f09344b84778 100644
--- a/metadata/interface.go
+++ b/metadata/interface.go
@@ -20,6 +20,7 @@ type AbsPaths []string
 type Manager interface {
 	Root() AbsPath
 	ComponentPaths() (AbsPaths, error)
+	LibPaths() (libPath, vendorLibPath AbsPath)
 	//
 	// TODO: Fill in methods as we need them.
 	//
diff --git a/metadata/manager.go b/metadata/manager.go
index 2bfb04c78525d726e38df915eb27a0e391b0a903..5da4157709e3ce4ec0f2024d0424c0acf4f89f15 100644
--- a/metadata/manager.go
+++ b/metadata/manager.go
@@ -126,7 +126,7 @@ func (m *manager) Root() AbsPath {
 }
 
 func (m *manager) ComponentPaths() (AbsPaths, error) {
-	paths := []string{}
+	paths := AbsPaths{}
 	err := afero.Walk(m.appFS, string(m.componentsPath), func(path string, info os.FileInfo, err error) error {
 		if err != nil {
 			return err
@@ -144,6 +144,10 @@ func (m *manager) ComponentPaths() (AbsPaths, error) {
 	return paths, nil
 }
 
+func (m *manager) LibPaths() (libPath, vendorLibPath AbsPath) {
+	return m.libPath, m.vendorLibDir
+}
+
 func (m *manager) cacheClusterSpecData(name string, specData []byte) error {
 	envPath := string(appendToAbsPath(m.schemaDir, name))
 	err := m.appFS.MkdirAll(envPath, os.ModePerm)
diff --git a/pkg/kubecfg/common.go b/pkg/kubecfg/common.go
deleted file mode 100644
index 305f707347db1204db5e103e56605223458bd15c..0000000000000000000000000000000000000000
--- a/pkg/kubecfg/common.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package kubecfg
-
-import (
-	"fmt"
-
-	"github.com/ksonnet/kubecfg/metadata"
-)
-
-func GetFiles(wd metadata.AbsPath, env *string, files []string) ([]string, error) {
-	envPresent := env != nil
-	filesPresent := len(files) > 0
-
-	// This is equivalent to: `if !xor(envPresent, filesPresent) {`
-	if envPresent && filesPresent {
-		return nil, fmt.Errorf("Either an environment name or a file list is required, but not both")
-	} else if !envPresent && !filesPresent {
-		return nil, fmt.Errorf("Must specify either an environment or a file list")
-	}
-
-	if envPresent {
-		manager, err := metadata.Find(wd)
-		if err != nil {
-			return nil, err
-		}
-
-		files, err = manager.ComponentPaths()
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return files, nil
-}