diff --git a/Makefile b/Makefile
index c50c15f228904321e13f792a2362673c22465302..7c6a301e67671f3240bbb141731668e7bbd1dd1f 100644
--- a/Makefile
+++ b/Makefile
@@ -44,15 +44,11 @@ docs:
 install:
 	$(GO) build -o $(GOPATH)/bin/ks $(GO_FLAGS) .
 
-test: gotest jsonnettest docstest
+test: gotest docstest
 
 gotest:
 	$(GO) test $(GO_FLAGS) $(GO_PACKAGES)
 
-jsonnettest: ks $(JSONNET_FILES)
-#	TODO: use `ks check` once implemented
-	./ks -J lib show -f $(KCFG_TEST_FILE) -f $(GUESTBOOK_FILE) >/dev/null
-
 docstest:
 	$(DOC_TEST_FILE)
 
diff --git a/cmd/apply.go b/cmd/apply.go
index c35e17c0f4c64e756332b047f23759e75b651f0d..9dbf8bcbd485322561dbe01c16f3c765835a7fee 100644
--- a/cmd/apply.go
+++ b/cmd/apply.go
@@ -63,9 +63,10 @@ var applyCmd = &cobra.Command{
 	Use:   "apply [env-name] [-f <file-or-dir>]",
 	Short: `Apply local configuration to remote cluster`,
 	RunE: func(cmd *cobra.Command, args []string) error {
-		if len(args) > 1 {
-			return fmt.Errorf("'apply' takes at most a single argument, that is the name of the environment")
+		if len(args) != 1 {
+			return fmt.Errorf("'apply' requires an environment name; use `env list` to see available environments\n\n%s", cmd.UsageString())
 		}
+		env := args[0]
 
 		flags := cmd.Flags()
 		var err error
@@ -92,18 +93,18 @@ var applyCmd = &cobra.Command{
 			return err
 		}
 
-		cwd, err := os.Getwd()
+		componentNames, err := flags.GetStringArray(flagComponent)
 		if err != nil {
 			return err
 		}
-		wd := metadata.AbsPath(cwd)
 
-		envSpec, err := parseEnvCmd(cmd, args)
+		cwd, err := os.Getwd()
 		if err != nil {
 			return err
 		}
+		wd := metadata.AbsPath(cwd)
 
-		c.ClientPool, c.Discovery, err = restClientPool(cmd, envSpec.env)
+		c.ClientPool, c.Discovery, err = restClientPool(cmd, &env)
 		if err != nil {
 			return err
 		}
@@ -113,7 +114,7 @@ var applyCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := expandEnvCmdObjs(cmd, envSpec, wd)
+		objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/delete.go b/cmd/delete.go
index c3e0750e71d3ee9409f2fdc11745f8e4a1b406ef..59eef3fcb435f730f0cfc09d79a6534295ca2a38 100644
--- a/cmd/delete.go
+++ b/cmd/delete.go
@@ -41,9 +41,10 @@ var deleteCmd = &cobra.Command{
 	Use:   "delete [env-name] [-f <file-or-dir>]",
 	Short: "Delete Kubernetes resources described in local config",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		if len(args) > 1 {
-			return fmt.Errorf("'delete' takes at most a single argument, that is the name of the environment")
+		if len(args) != 1 {
+			return fmt.Errorf("'delete' requires an environment name; use `env list` to see available environments\n\n%s", cmd.UsageString())
 		}
+		env := args[0]
 
 		flags := cmd.Flags()
 		var err error
@@ -55,18 +56,18 @@ var deleteCmd = &cobra.Command{
 			return err
 		}
 
-		cwd, err := os.Getwd()
+		componentNames, err := flags.GetStringArray(flagComponent)
 		if err != nil {
 			return err
 		}
-		wd := metadata.AbsPath(cwd)
 
-		envSpec, err := parseEnvCmd(cmd, args)
+		cwd, err := os.Getwd()
 		if err != nil {
 			return err
 		}
+		wd := metadata.AbsPath(cwd)
 
-		c.ClientPool, c.Discovery, err = restClientPool(cmd, envSpec.env)
+		c.ClientPool, c.Discovery, err = restClientPool(cmd, &env)
 		if err != nil {
 			return err
 		}
@@ -76,7 +77,7 @@ var deleteCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := expandEnvCmdObjs(cmd, envSpec, wd)
+		objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/diff.go b/cmd/diff.go
index f4e3c6a353274995448b4b662a05dfed55e855d7..7aaf80cc9dfdffffe78335574e9787a0fc2baac9 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -59,7 +59,7 @@ var diffCmd = &cobra.Command{
 		}
 		wd := metadata.AbsPath(cwd)
 
-		files, err := flags.GetStringArray(flagFile)
+		componentNames, err := flags.GetStringArray(flagComponent)
 		if err != nil {
 			return err
 		}
@@ -79,7 +79,7 @@ var diffCmd = &cobra.Command{
 			return err
 		}
 
-		c, err := initDiffCmd(cmd, wd, env1, env2, files, diffStrategy)
+		c, err := initDiffCmd(cmd, wd, env1, env2, componentNames, diffStrategy)
 		if err != nil {
 			return err
 		}
@@ -177,13 +177,12 @@ func initDiffSingleEnv(env, diffStrategy string, files []string, cmd *cobra.Comm
 		return nil, fmt.Errorf("single <env> argument with prefix 'local:' or 'remote:' not allowed")
 	}
 
-	envSpec := &envSpec{env: &env, files: files}
-	c.Client.APIObjects, err = expandEnvCmdObjs(cmd, envSpec, wd)
+	c.Client.APIObjects, err = expandEnvCmdObjs(cmd, env, files, wd)
 	if err != nil {
 		return nil, err
 	}
 
-	c.Client.ClientPool, c.Client.Discovery, err = restClientPool(cmd, envSpec.env)
+	c.Client.ClientPool, c.Client.Discovery, err = restClientPool(cmd, &env)
 	if err != nil {
 		return nil, err
 	}
@@ -299,12 +298,15 @@ func expandEnvObjs(cmd *cobra.Command, env string, manager metadata.Manager) ([]
 	}
 
 	libPath, vendorPath, envLibPath, envComponentPath, envParamsPath := manager.LibPaths(env)
-
 	componentPaths, err := manager.ComponentPaths()
 	if err != nil {
 		return nil, err
 	}
-	baseObj := constructBaseObj(componentPaths)
+
+	baseObj, err := constructBaseObj(componentPaths, nil)
+	if err != nil {
+		return nil, err
+	}
 	params := importParams(string(envParamsPath))
 
 	expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(envLibPath)}, expander.FlagJpath...)
diff --git a/cmd/root.go b/cmd/root.go
index 9f4fff3d70eadba6da0c77001ccc90f537dc815b..7a4045b9be1d67bcff1b005695d16d1ebc77c2e4 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -59,8 +59,8 @@ const (
 
 	// For use in the commands (e.g., diff, apply, delete) that require either an
 	// environment or the -f flag.
-	flagFile      = "file"
-	flagFileShort = "f"
+	flagComponent      = "component"
+	flagComponentShort = "c"
 )
 
 var clientConfig clientcmd.ClientConfig
@@ -302,33 +302,10 @@ func restClientPool(cmd *cobra.Command, envName *string) (dynamic.ClientPool, di
 	return restClient(cmd, envName, clientConfig, &overrides)
 }
 
-type envSpec struct {
-	env   *string
-	files []string
-}
-
 // addEnvCmdFlags adds the flags that are common to the family of commands
 // whose form is `[<env>|-f <file-name>]`, e.g., `apply` 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., `apply` and `delete`.
-func parseEnvCmd(cmd *cobra.Command, args []string) (*envSpec, error) {
-	flags := cmd.Flags()
-
-	files, err := flags.GetStringArray(flagFile)
-	if err != nil {
-		return nil, err
-	}
-
-	var env *string
-	if len(args) == 1 {
-		env = &args[0]
-	}
-
-	return &envSpec{env: env, files: files}, nil
+	cmd.PersistentFlags().StringArrayP(flagComponent, flagComponentShort, nil, "Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)")
 }
 
 // overrideCluster ensures that the server specified in the environment is
@@ -398,55 +375,41 @@ func overrideCluster(envName string, clientConfig clientcmd.ClientConfig, overri
 // 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, envSpec *envSpec, cwd metadata.AbsPath) ([]*unstructured.Unstructured, error) {
+func expandEnvCmdObjs(cmd *cobra.Command, env string, components []string, cwd metadata.AbsPath) ([]*unstructured.Unstructured, error) {
 	expander, err := newExpander(cmd)
 	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.
+	// Set up the template expander to be able to expand the ksonnet application.
 	//
 
-	envPresent := envSpec.env != nil
-	filesPresent := len(envSpec.files) > 0
-
-	if !envPresent && !filesPresent {
-		return nil, fmt.Errorf("Must specify either an environment or a file list, or both")
+	manager, err := metadata.Find(cwd)
+	if err != nil {
+		return nil, err
 	}
 
-	fileNames := envSpec.files
-	if envPresent {
-		manager, err := metadata.Find(cwd)
-		if err != nil {
-			return nil, err
-		}
-
-		libPath, vendorPath, envLibPath, envComponentPath, envParamsPath := manager.LibPaths(*envSpec.env)
-		expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(envLibPath)}, expander.FlagJpath...)
-
-		componentPaths, err := manager.ComponentPaths()
-		if err != nil {
-			return nil, err
-		}
+	libPath, vendorPath, envLibPath, envComponentPath, envParamsPath := manager.LibPaths(env)
+	expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(envLibPath)}, expander.FlagJpath...)
 
-		baseObj := constructBaseObj(componentPaths)
-		params := importParams(string(envParamsPath))
-		expander.ExtCodes = append([]string{baseObj, params}, expander.ExtCodes...)
-
-		if !filesPresent {
+	componentPaths, err := manager.ComponentPaths()
+	if err != nil {
+		return nil, err
+	}
 
-			fileNames = []string{string(envComponentPath)}
-		}
+	baseObj, err := constructBaseObj(componentPaths, components)
+	if err != nil {
+		return nil, err
 	}
+	params := importParams(string(envParamsPath))
+	expander.ExtCodes = append([]string{baseObj, params}, expander.ExtCodes...)
 
 	//
-	// Expand templates.
+	// Expand the ksonnet app as rendered for environment `env`.
 	//
 
-	return expander.Expand(fileNames)
+	return expander.Expand([]string{string(envComponentPath)})
 }
 
 // constructBaseObj constructs the base Jsonnet object that represents k-v
@@ -456,21 +419,75 @@ func expandEnvCmdObjs(cmd *cobra.Command, envSpec *envSpec, cwd metadata.AbsPath
 //      foo: import "components/foo.jsonnet"
 //      "foo-bar": import "components/foo-bar.jsonnet"
 //   }
-func constructBaseObj(paths []string) string {
+func constructBaseObj(componentPaths, componentNames []string) (string, error) {
+	// IMPLEMENTATION NOTE: If one or more `componentNames` exist, it is
+	// sufficient to simply omit every name that does not appear in the list. This
+	// is because we know every field of the base object will contain _only_ an
+	// `import` node (see example object in the function-heading comment). This
+	// would not be true in cases where one field can reference another field; in
+	// this case, one would need to generate the entire object, and filter that.
+	//
+	// Hence, a word of caution: if the base object ever becomes more complex, you
+	// will need to change the way this function performs filtering, as it will
+	// lead to very confusing bugs.
+
+	shouldFilter := len(componentNames) > 0
+	filter := map[string]string{}
+	for _, name := range componentNames {
+		filter[name] = ""
+	}
+
+	// Add every component we know about to the base object.
 	var obj bytes.Buffer
 	obj.WriteString("{\n")
-	for _, p := range paths {
+	for _, p := range componentPaths {
 		ext := path.Ext(p)
-		if path.Ext(p) != ".jsonnet" {
+		componentName := strings.TrimSuffix(path.Base(p), ext)
+
+		// Filter! If the filter has more than 1 element and the component name is
+		// not in the filter, skip.
+		if _, exists := filter[componentName]; shouldFilter && !exists {
+			continue
+		} else if shouldFilter && exists {
+			delete(filter, componentName)
+		}
+
+		// Generate import statement.
+		var importExpr string
+		switch ext {
+		case ".jsonnet":
+			importExpr = fmt.Sprintf(`import "%s"`, p)
+
+		// TODO: Pull in YAML and JSON when we build the base object.
+		//
+		// case ".yaml", ".yml":
+		// 	importExpr = fmt.Sprintf(`util.parseYaml("%s")`, p)
+		// case ".json":
+		// 	importExpr = fmt.Sprintf(`util.parseJson("%s")`, p)
+		default:
 			continue
 		}
 
-		name := strings.TrimSuffix(path.Base(p), ext)
-		name = params.SanitizeComponent(name)
-		fmt.Fprintf(&obj, "  %s: import \"%s\",\n", name, p)
+		// Emit object field. Sanitize the name to guarantee we generate valid
+		// Jsonnet.
+		componentName = params.SanitizeComponent(componentName)
+		fmt.Fprintf(&obj, "  %s: %s,\n", componentName, importExpr)
 	}
-	obj.WriteString("}\n")
-	return fmt.Sprintf("%s=%s", metadata.ComponentsExtCodeKey, obj.String())
+
+	// Check that we found all the components the user asked for.
+	if shouldFilter && len(filter) != 0 {
+		names := []string{}
+		for name := range filter {
+			names = append(names, "'"+name+"'")
+		}
+		return "", fmt.Errorf("Failed to filter components; the following components don't exist: [ %s ]", strings.Join(names, ","))
+	}
+
+	// Terminate object.
+	fmt.Fprintf(&obj, "}\n")
+
+	// Emit `base.libsonnet`.
+	return fmt.Sprintf("%s=%s", metadata.ComponentsExtCodeKey, obj.String()), nil
 }
 
 func importParams(path string) string {
diff --git a/cmd/root_test.go b/cmd/root_test.go
index d5539cdc88302ba569148af3839aaa1b416733c7..85803c56d100dfff0f04d4e3423ab10aa779fc5a 100644
--- a/cmd/root_test.go
+++ b/cmd/root_test.go
@@ -78,7 +78,11 @@ func TestConstructBaseObj(t *testing.T) {
 	}
 
 	for _, s := range tests {
-		res := constructBaseObj(s.inputPaths)
+		res, err := constructBaseObj(s.inputPaths, nil)
+		if err != nil {
+			t.Error(err)
+		}
+
 		if res != fmt.Sprintf("__ksonnet/components=%s", s.expected) {
 			t.Errorf("Wrong object constructed\n  expected: %v\n  got: %v", s.expected, res)
 		}
diff --git a/cmd/show.go b/cmd/show.go
index c27e20f2cae87bbbd783f5fc564634a21231c29e..0d93209b16cf4975ef3bd08a3ac3f16870740f21 100644
--- a/cmd/show.go
+++ b/cmd/show.go
@@ -44,7 +44,7 @@ each defining a ksonnet component, are expanded into their JSON or YAML equivale
 Any parameters in these Jsonnet manifests are resolved based on environment-specific values.
 
 When NO component is specified (no ` + "`-c`" + ` flag), this command expands all of the files in the ` +
-"`components/`" + ` directory into a list of resource definitions. This is the YAML version
+		"`components/`" + ` directory into a list of resource definitions. This is the YAML version
 of what gets deployed to your cluster with ` + "`ks apply <env>`" + `.
 
 When a component IS specified via the ` + "`-c`" + ` flag, this command only expands the manifest for that
@@ -60,13 +60,19 @@ ks show prod -c redis -o json
 ks show dev -c redis -c nginx-server
 `,
 	RunE: func(cmd *cobra.Command, args []string) error {
-		if len(args) > 1 {
-			return fmt.Errorf("'show' takes at most a single argument, that is the name of the environment")
+		if len(args) != 1 {
+			return fmt.Errorf("'show' requires an environment name; use `env list` to see available environments\n\n%s", cmd.UsageString())
 		}
+		env := args[0]
 
 		flags := cmd.Flags()
 		var err error
 
+		componentNames, err := flags.GetStringArray(flagComponent)
+		if err != nil {
+			return err
+		}
+
 		c := kubecfg.ShowCmd{}
 
 		c.Format, err = flags.GetString(flagFormat)
@@ -80,12 +86,7 @@ ks show dev -c redis -c nginx-server
 		}
 		wd := metadata.AbsPath(cwd)
 
-		envSpec, err := parseEnvCmd(cmd, args)
-		if err != nil {
-			return err
-		}
-
-		objs, err := expandEnvCmdObjs(cmd, envSpec, wd)
+		objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/show_test.go b/cmd/show_test.go
index 6fc117b504b3968b6187bb118906c6cdd8491936..c364d63c32de7b239c60c98f35e272c877dec953 100644
--- a/cmd/show_test.go
+++ b/cmd/show_test.go
@@ -39,6 +39,24 @@ func cmdOutput(t *testing.T, args []string) string {
 }
 
 func TestShow(t *testing.T) {
+	// cd to the test directory we can run the `show` command.
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = os.Chdir("../testdata/testapp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err = os.Chdir(wd)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	// Run the show command.
 	formats := map[string]func(string) (interface{}, error){
 		"json": func(text string) (ret interface{}, err error) {
 			err = json.Unmarshal([]byte(text), &ret)
@@ -80,13 +98,14 @@ func TestShow(t *testing.T) {
 		os.Setenv("anVar", "aVal2")
 		defer os.Unsetenv("anVar")
 
-		output := cmdOutput(t, []string{"show",
-			"-J", filepath.FromSlash("../testdata/lib"),
+		output := cmdOutput(t, []string{
+			"show",
+			"default",
 			"-o", format,
-			"-f", filepath.FromSlash("../testdata/test.jsonnet"),
+			"-c", "test",
 			"-V", "aVar=aVal",
 			"-V", "anVar",
-			"--ext-str-file", "filevar=" + filepath.FromSlash("../testdata/extvar.file"),
+			"--ext-str-file", "filevar=" + filepath.FromSlash("../extvar.file"),
 		})
 
 		t.Log("output is", output)
diff --git a/cmd/validate.go b/cmd/validate.go
index 141dd78ccf299b621b0e8a23609ac06d30832bb1..8c3074f4e7ac6dba7b157f5445cc4fd76f9909b8 100644
--- a/cmd/validate.go
+++ b/cmd/validate.go
@@ -36,10 +36,12 @@ var validateCmd = &cobra.Command{
 	Use:   "validate [env-name] [-f <file-or-dir>]",
 	Short: "Compare generated manifest against server OpenAPI spec",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		if len(args) > 1 {
-			return fmt.Errorf("'validate' takes at most a single argument, that is the name of the environment")
+		if len(args) != 1 {
+			return fmt.Errorf("'validate' requires an environment name; use `env list` to see available environments\n\n%s", cmd.UsageString())
 		}
+		env := args[0]
 
+		flags := cmd.Flags()
 		var err error
 
 		c := kubecfg.ValidateCmd{}
@@ -50,7 +52,7 @@ var validateCmd = &cobra.Command{
 		}
 		wd := metadata.AbsPath(cwd)
 
-		envSpec, err := parseEnvCmd(cmd, args)
+		componentNames, err := flags.GetStringArray(flagComponent)
 		if err != nil {
 			return err
 		}
@@ -60,7 +62,7 @@ var validateCmd = &cobra.Command{
 			return err
 		}
 
-		objs, err := expandEnvCmdObjs(cmd, envSpec, wd)
+		objs, err := expandEnvCmdObjs(cmd, env, componentNames, wd)
 		if err != nil {
 			return err
 		}
diff --git a/docs/cli-reference/ks_apply.md b/docs/cli-reference/ks_apply.md
index 9a2a19b244fe8e0d742a62a5b1fdc36fb05c23e8..a92023b28b596c11a7f8dcdfbc278a7f444d68da 100644
--- a/docs/cli-reference/ks_apply.md
+++ b/docs/cli-reference/ks_apply.md
@@ -48,12 +48,12 @@ ks apply dev --dry-run
       --client-certificate string      Path to a client certificate file for TLS
       --client-key string              Path to a client key file for TLS
       --cluster string                 The name of the kubeconfig cluster to use
+  -c, --component stringArray          Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)
       --context string                 The name of the kubeconfig context to use
       --create                         Create missing resources (default true)
       --dry-run                        Perform only read-only operations
   -V, --ext-str stringSlice            Values of external variables
       --ext-str-file stringSlice       Read external variable from a file
-  -f, --file stringArray               Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)
       --gc-tag string                  Add this tag to updated objects, and garbage collect existing objects with this tag and not in config
       --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
   -J, --jpath stringSlice              Additional jsonnet library search path
diff --git a/docs/cli-reference/ks_delete.md b/docs/cli-reference/ks_delete.md
index 77c3071ccedd794b5d66c146a95e7dbb11ff473a..33c09135009c090a49a6a6e74aa98a2ea00a14be 100644
--- a/docs/cli-reference/ks_delete.md
+++ b/docs/cli-reference/ks_delete.md
@@ -43,10 +43,10 @@ ks delete --kubeconfig=./kubeconfig -f ./pod.yaml
       --client-certificate string      Path to a client certificate file for TLS
       --client-key string              Path to a client key file for TLS
       --cluster string                 The name of the kubeconfig cluster to use
+  -c, --component stringArray          Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)
       --context string                 The name of the kubeconfig context to use
   -V, --ext-str stringSlice            Values of external variables
       --ext-str-file stringSlice       Read external variable from a file
-  -f, --file stringArray               Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)
       --grace-period int               Number of seconds given to resources to terminate gracefully. A negative value is ignored (default -1)
       --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
   -J, --jpath stringSlice              Additional jsonnet library search path
diff --git a/docs/cli-reference/ks_diff.md b/docs/cli-reference/ks_diff.md
index dab22535373599a2a059add6efd7d242b4841464..c64fc0033e42b708351ac41b244ccaa1f9d6f302 100644
--- a/docs/cli-reference/ks_diff.md
+++ b/docs/cli-reference/ks_diff.md
@@ -52,10 +52,10 @@ ks diff --kubeconfig=./kubeconfig -f ./pod.yaml
 ### Options
 
 ```
+  -c, --component stringArray         Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)
       --diff-strategy string          Diff strategy, all or subset. (default "all")
   -V, --ext-str stringSlice           Values of external variables
       --ext-str-file stringSlice      Read external variable from a file
-  -f, --file stringArray              Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)
   -J, --jpath stringSlice             Additional jsonnet library search path
       --resolve-images string         Change implementation of resolveImage native function. One of: noop, registry (default "noop")
       --resolve-images-error string   Action when resolveImage fails. One of ignore,warn,error (default "warn")
diff --git a/docs/cli-reference/ks_show.md b/docs/cli-reference/ks_show.md
index c245f4d01d7c811ccb46bcfe72c8d7adc09b483b..508b7efd4d6c1de23e9d706278661217d1db14f6 100644
--- a/docs/cli-reference/ks_show.md
+++ b/docs/cli-reference/ks_show.md
@@ -37,9 +37,9 @@ ks show dev -c redis -c nginx-server
 ### Options
 
 ```
+  -c, --component stringArray         Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)
   -V, --ext-str stringSlice           Values of external variables
       --ext-str-file stringSlice      Read external variable from a file
-  -f, --file stringArray              Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)
   -o, --format string                 Output format.  Supported values are: json, yaml (default "yaml")
   -J, --jpath stringSlice             Additional jsonnet library search path
       --resolve-images string         Change implementation of resolveImage native function. One of: noop, registry (default "noop")
diff --git a/docs/cli-reference/ks_validate.md b/docs/cli-reference/ks_validate.md
index 272397c922d237e8b076fcf0154b6e7e00b71af7..bdc9cf63a02917b89c4b2906859a1b503ff4080e 100644
--- a/docs/cli-reference/ks_validate.md
+++ b/docs/cli-reference/ks_validate.md
@@ -43,10 +43,10 @@ ksonnet validate -f ./pod.jsonnet
       --client-certificate string      Path to a client certificate file for TLS
       --client-key string              Path to a client key file for TLS
       --cluster string                 The name of the kubeconfig cluster to use
+  -c, --component stringArray          Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)
       --context string                 The name of the kubeconfig context to use
   -V, --ext-str stringSlice            Values of external variables
       --ext-str-file stringSlice       Read external variable from a file
-  -f, --file stringArray               Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)
       --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
   -J, --jpath stringSlice              Additional jsonnet library search path
       --kubeconfig string              Path to a kube config. Only required if out-of-cluster
diff --git a/testdata/testapp/.ksonnet/registries/incubator/93cd219c5ef77adaade43da0f95a4bebd6acc422.yaml b/testdata/testapp/.ksonnet/registries/incubator/93cd219c5ef77adaade43da0f95a4bebd6acc422.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a8dc7f1e916971a6935f26d778f15f90b18a808b
--- /dev/null
+++ b/testdata/testapp/.ksonnet/registries/incubator/93cd219c5ef77adaade43da0f95a4bebd6acc422.yaml
@@ -0,0 +1,39 @@
+apiVersion: "0.1"
+gitVersion:
+  commitSha: 93cd219c5ef77adaade43da0f95a4bebd6acc422
+  refSpec: test-reg
+kind: ksonnet.io/registry
+libraries:
+  apache:
+    path: apache
+    version: test-reg
+  efk:
+    path: efk
+    version: test-reg
+  mariadb:
+    path: mariadb
+    version: test-reg
+  memcached:
+    path: memcached
+    version: test-reg
+  mongodb:
+    path: mongodb
+    version: test-reg
+  mysql:
+    path: mysql
+    version: test-reg
+  nginx:
+    path: nginx
+    version: test-reg
+  node:
+    path: node
+    version: test-reg
+  postgres:
+    path: postgres
+    version: test-reg
+  redis:
+    path: redis
+    version: test-reg
+  tomcat:
+    path: tomcat
+    version: test-reg
diff --git a/testdata/testapp/app.yaml b/testdata/testapp/app.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5a24585d72fe8a2faf48ad7730715097ccd78222
--- /dev/null
+++ b/testdata/testapp/app.yaml
@@ -0,0 +1,11 @@
+apiVersion: 0.0.1
+kind: ksonnet.io/app
+name: test-app
+registries:
+  incubator:
+    gitVersion:
+      commitSha: 93cd219c5ef77adaade43da0f95a4bebd6acc422
+      refSpec: test-reg
+    protocol: github
+    uri: github.com/ksonnet/parts/tree/test-reg/incubator
+version: 0.0.1
diff --git a/testdata/testapp/components/params.libsonnet b/testdata/testapp/components/params.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..2f63e926d38dad98b0c895e6b29ecddd4841aa13
--- /dev/null
+++ b/testdata/testapp/components/params.libsonnet
@@ -0,0 +1,13 @@
+{
+  global: {
+    // User-defined global parameters; accessible to all component and environments, Ex:
+    // replicas: 4,
+  },
+  components: {
+    // Component-level parameters, defined initially from 'ks prototype use ...'
+    // Each object below should correspond to a component in the components/ directory
+    "test-ns": {
+      name: "test",
+    },
+  },
+}
diff --git a/testdata/testapp/components/test-ns-json.json b/testdata/testapp/components/test-ns-json.json
new file mode 100644
index 0000000000000000000000000000000000000000..55ea1b9280a9df78ee0c668ef972bfcc0becc037
--- /dev/null
+++ b/testdata/testapp/components/test-ns-json.json
@@ -0,0 +1,10 @@
+{
+  "apiVersion": "v1",
+  "kind": "Namespace",
+  "metadata": {
+    "labels": {
+      "name": "test-ns"
+    },
+    "name": "test-ns"
+  }
+}
diff --git a/testdata/testapp/components/test-ns-yaml.yaml b/testdata/testapp/components/test-ns-yaml.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..333ec4a678e11e5d1adf2d37f0b73b93c75237ad
--- /dev/null
+++ b/testdata/testapp/components/test-ns-yaml.yaml
@@ -0,0 +1,7 @@
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  labels:
+    name: test-ns
+  name: test-ns
diff --git a/testdata/testapp/components/test-ns.jsonnet b/testdata/testapp/components/test-ns.jsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..161b776bbcdda6e971f5eacc6f30ab1b64e748f3
--- /dev/null
+++ b/testdata/testapp/components/test-ns.jsonnet
@@ -0,0 +1,10 @@
+{
+  apiVersion: "v1",
+  kind: "Namespace",
+  metadata: {
+    labels: {
+      name: "test-ns"
+    },
+    name: "test-ns",
+  },
+}
diff --git a/testdata/test.jsonnet b/testdata/testapp/components/test.jsonnet
similarity index 100%
rename from testdata/test.jsonnet
rename to testdata/testapp/components/test.jsonnet
diff --git a/testdata/lib/test.libsonnet b/testdata/testapp/components/test.libsonnet
similarity index 100%
rename from testdata/lib/test.libsonnet
rename to testdata/testapp/components/test.libsonnet
diff --git a/testdata/testapp/environments/base.libsonnet b/testdata/testapp/environments/base.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..a129affb1f33ebfb1e2ab26a016935ee2b33ea06
--- /dev/null
+++ b/testdata/testapp/environments/base.libsonnet
@@ -0,0 +1,4 @@
+local components = std.extVar("__ksonnet/components");
+components + {
+  // Insert user-specified overrides here.
+}
diff --git a/testdata/testapp/environments/default/main.jsonnet b/testdata/testapp/environments/default/main.jsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..23010d3d5012f8954d1cb7b4b4ad62af5d56e9e6
--- /dev/null
+++ b/testdata/testapp/environments/default/main.jsonnet
@@ -0,0 +1,7 @@
+local base = import "../base.libsonnet";
+local k = import "k.libsonnet";
+
+base + {
+  // Insert user-specified overrides here. For example if a component is named "nginx-deployment", you might have something like:
+  //   "nginx-deployment"+: k.deployment.mixin.metadata.labels({foo: "bar"})
+}
diff --git a/testdata/testapp/environments/default/params.libsonnet b/testdata/testapp/environments/default/params.libsonnet
new file mode 100644
index 0000000000000000000000000000000000000000..e5f5e092df3c7961fbd2b22b92867d31b2eeba65
--- /dev/null
+++ b/testdata/testapp/environments/default/params.libsonnet
@@ -0,0 +1,10 @@
+local params = import "/Users/alex/src/go/src/github.com/ksonnet/ksonnet/testdata/test-app/components/params.libsonnet";
+params + {
+  components +: {
+    // Insert component parameter overrides here. Ex:
+    // guestbook +: {
+    //   name: "guestbook-dev",
+    //   replicas: params.global.replicas,
+    // },
+  },
+}
diff --git a/testdata/testapp/environments/default/spec.json b/testdata/testapp/environments/default/spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..97c96d166db1ff75775a0075ed07e702716604c8
--- /dev/null
+++ b/testdata/testapp/environments/default/spec.json
@@ -0,0 +1,4 @@
+{
+  "server": "example.com",
+  "namespace": "example-ns"
+}
\ No newline at end of file