diff --git a/cmd/diff.go b/cmd/diff.go
index def0ff548ef28b993fcd0f49fcc887143f46293d..93dcec1ddecc9998ecbf6e4cdacb7e0a98f48058 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -315,7 +315,8 @@ func expandEnvObjs(cmd *cobra.Command, env string, manager metadata.Manager) ([]
 		return nil, err
 	}
 
-	libPath, vendorPath, envLibPath, envComponentPath, envParamsPath := manager.LibPaths(env)
+	libPath, vendorPath := manager.LibPaths()
+	metadataPath, mainPath, paramsPath, specPath := manager.EnvPaths(env)
 	componentPaths, err := manager.ComponentPaths()
 	if err != nil {
 		return nil, err
@@ -325,12 +326,13 @@ func expandEnvObjs(cmd *cobra.Command, env string, manager metadata.Manager) ([]
 	if err != nil {
 		return nil, err
 	}
-	params := importParams(string(envParamsPath))
+	params := importParams(string(paramsPath))
+	spec := importEnv(string(specPath))
 
-	expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(envLibPath)}, expander.FlagJpath...)
-	expander.ExtCodes = append([]string{baseObj, params}, expander.ExtCodes...)
+	expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(metadataPath)}, expander.FlagJpath...)
+	expander.ExtCodes = append([]string{baseObj, params, spec}, expander.ExtCodes...)
 
-	envFiles := []string{string(envComponentPath)}
+	envFiles := []string{string(mainPath)}
 
 	return expander.Expand(envFiles)
 }
diff --git a/cmd/prototype.go b/cmd/prototype.go
index ad2f909e9db525a6ba1e656697e3ecc75e619e34..5df4520bb1d4e111d750fc0a525b5e8463c8656c 100644
--- a/cmd/prototype.go
+++ b/cmd/prototype.go
@@ -449,7 +449,7 @@ expand prototypes into Jsonnet files.
        ks prototype use io.ksonnet.pkg.single-port-deployment nginx-depl \
          --image=nginx
 
-  If the optional ` + "`--name`"  + ` tag is not specified, all Kubernetes API resources
+  If the optional ` + "`--name`" + ` tag is not specified, all Kubernetes API resources
   declared by this prototype use this argument as their own ` + "`metadata.name`" + `
 
 3. Prototypes can be further customized by passing in **parameters** via additional
@@ -503,7 +503,10 @@ func expandPrototype(proto *prototype.SpecificationSchema, templateType prototyp
 		if !utils.IsASCIIIdentifier(componentName) {
 			componentsText = fmt.Sprintf(`components["%s"]`, componentName)
 		}
-		template = append([]string{`local params = std.extVar("` + metadata.ParamsExtCodeKey + `").` + componentsText + ";"}, template...)
+		template = append([]string{
+			`local env = std.extVar("` + metadata.EnvExtCodeKey + `");`,
+			`local params = std.extVar("` + metadata.ParamsExtCodeKey + `").` + componentsText + ";"},
+			template...)
 		return jsonnet.Parse(componentName, strings.Join(template, "\n"))
 	}
 
diff --git a/cmd/root.go b/cmd/root.go
index db6403c2cf7a276ef36d90aa239c35edc0249026..947b07e4bc139fad3034a55541828828e27eab64 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -399,8 +399,10 @@ func expandEnvCmdObjs(cmd *cobra.Command, env string, components []string, cwd m
 		return nil, err
 	}
 
-	libPath, vendorPath, envLibPath, envComponentPath, envParamsPath := manager.LibPaths(env)
-	expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(envLibPath)}, expander.FlagJpath...)
+	libPath, vendorPath := manager.LibPaths()
+	metadataPath, mainPath, paramsPath, specPath := manager.EnvPaths(env)
+
+	expander.FlagJpath = append([]string{string(libPath), string(vendorPath), string(metadataPath)}, expander.FlagJpath...)
 
 	componentPaths, err := manager.ComponentPaths()
 	if err != nil {
@@ -411,14 +413,20 @@ func expandEnvCmdObjs(cmd *cobra.Command, env string, components []string, cwd m
 	if err != nil {
 		return nil, err
 	}
-	params := importParams(string(envParamsPath))
-	expander.ExtCodes = append([]string{baseObj, params}, expander.ExtCodes...)
+
+	//
+	// Set up ExtCodes to resolve runtime variables such as the environment namespace.
+	//
+
+	params := importParams(string(paramsPath))
+	spec := importEnv(string(specPath))
+	expander.ExtCodes = append([]string{baseObj, params, spec}, expander.ExtCodes...)
 
 	//
 	// Expand the ksonnet app as rendered for environment `env`.
 	//
 
-	return expander.Expand([]string{string(envComponentPath)})
+	return expander.Expand([]string{string(mainPath)})
 }
 
 // constructBaseObj constructs the base Jsonnet object that represents k-v
@@ -502,3 +510,7 @@ func constructBaseObj(componentPaths, componentNames []string) (string, error) {
 func importParams(path string) string {
 	return fmt.Sprintf(`%s=import "%s"`, metadata.ParamsExtCodeKey, path)
 }
+
+func importEnv(path string) string {
+	return fmt.Sprintf(`%s=import "%s"`, metadata.EnvExtCodeKey, path)
+}
diff --git a/metadata/interface.go b/metadata/interface.go
index e406a5715e3990d0b3b2927e71573dbd7c9d4d93..90c1b7461da28c417dfb1452c3f60b37d3881cc2 100644
--- a/metadata/interface.go
+++ b/metadata/interface.go
@@ -45,7 +45,8 @@ type AbsPaths []string
 // libraries; and other non-core-application tasks.
 type Manager interface {
 	Root() AbsPath
-	LibPaths(envName string) (libPath, vendorPath, envLibPath, envComponentPath, envParamsPath AbsPath)
+	LibPaths() (libPath, vendorPath AbsPath)
+	EnvPaths(env string) (metadataPath, mainPath, paramsPath, specPath AbsPath)
 
 	// Components API.
 	ComponentPaths() (AbsPaths, error)
diff --git a/metadata/manager.go b/metadata/manager.go
index 4aab3ffeff6dc5e9c25673a2ee52132107ac8ebb..d477a1b49d90a649a0c44089507486737fefa14c 100644
--- a/metadata/manager.go
+++ b/metadata/manager.go
@@ -51,7 +51,9 @@ const (
 
 	// ComponentsExtCodeKey is the ExtCode key for component imports
 	ComponentsExtCodeKey = "__ksonnet/components"
-	// ParamsExtCodeKey is the ExtCode key for importing environment parameters
+	// EnvExtCodeKey is the ExtCode key for importing environment metadata
+	EnvExtCodeKey = "__ksonnet/environments"
+	// ParamsExtCodeKey is the ExtCode key for importing component parameters
 	ParamsExtCodeKey = "__ksonnet/params"
 
 	// User-level ksonnet directories.
@@ -197,10 +199,23 @@ func (m *manager) Root() AbsPath {
 	return m.rootPath
 }
 
-func (m *manager) LibPaths(envName string) (libPath, vendorPath, envLibPath, envComponentPath, envParamsPath AbsPath) {
-	envPath := appendToAbsPath(m.environmentsPath, envName)
-	return m.libPath, m.vendorPath, appendToAbsPath(envPath, metadataDirName),
-		appendToAbsPath(envPath, envFileName), appendToAbsPath(envPath, componentParamsFile)
+func (m *manager) LibPaths() (libPath, vendorPath AbsPath) {
+	return m.libPath, m.vendorPath
+}
+
+func (m *manager) EnvPaths(env string) (metadataPath, mainPath, paramsPath, specPath AbsPath) {
+	envPath := appendToAbsPath(m.environmentsPath, env)
+
+	// .metadata directory
+	metadataPath = appendToAbsPath(envPath, metadataDirName)
+	// main.jsonnet file
+	mainPath = appendToAbsPath(envPath, envFileName)
+	// params.libsonnet file
+	paramsPath = appendToAbsPath(envPath, componentParamsFile)
+	// spec.json file
+	specPath = appendToAbsPath(envPath, specFilename)
+
+	return
 }
 
 func (m *manager) GetComponentParams(component string) (param.Params, error) {
diff --git a/metadata/manager_test.go b/metadata/manager_test.go
index 72cb32d2f43aac834fd0e2b6e04f40bb817bba0d..9c4cf463005d0c697b6c00f40be286ebd0b21fef 100644
--- a/metadata/manager_test.go
+++ b/metadata/manager_test.go
@@ -210,26 +210,38 @@ func TestLibPaths(t *testing.T) {
 	appName := "test-lib-paths"
 	expectedVendorPath := path.Join(appName, vendorDir)
 	expectedLibPath := path.Join(appName, libDir)
-	expectedEnvLibPath := path.Join(appName, environmentsDir, mockEnvName, metadataDirName)
-	expectedEnvComponentPath := path.Join(appName, environmentsDir, mockEnvName, envFileName)
-	expectedEnvParamsPath := path.Join(appName, environmentsDir, mockEnvName, paramsFileName)
 	m := mockEnvironments(t, appName)
 
-	libPath, vendorPath, envLibPath, envComponentPath, envParamsPath := m.LibPaths(mockEnvName)
+	libPath, vendorPath := m.LibPaths()
 	if string(libPath) != expectedLibPath {
 		t.Fatalf("Expected lib path to be:\n  '%s'\n, got:\n  '%s'", expectedLibPath, libPath)
 	}
 	if string(vendorPath) != expectedVendorPath {
 		t.Fatalf("Expected vendor lib path to be:\n  '%s'\n, got:\n  '%s'", expectedVendorPath, vendorPath)
 	}
-	if string(envLibPath) != expectedEnvLibPath {
-		t.Fatalf("Expected environment lib path to be:\n  '%s'\n, got:\n  '%s'", expectedEnvLibPath, envLibPath)
+}
+
+func TestEnvPaths(t *testing.T) {
+	appName := "test-env-paths"
+	expectedMetadataPath := path.Join(appName, environmentsDir, mockEnvName, metadataDirName)
+	expectedMainPath := path.Join(appName, environmentsDir, mockEnvName, envFileName)
+	expectedParamsPath := path.Join(appName, environmentsDir, mockEnvName, paramsFileName)
+	expectedSpecPath := path.Join(appName, environmentsDir, mockEnvName, specFilename)
+	m := mockEnvironments(t, appName)
+
+	metadataPath, mainPath, paramsPath, specPath := m.EnvPaths(mockEnvName)
+
+	if string(metadataPath) != expectedMetadataPath {
+		t.Fatalf("Expected environment metadata dir path to be:\n  '%s'\n, got:\n  '%s'", expectedMetadataPath, metadataPath)
+	}
+	if string(mainPath) != expectedMainPath {
+		t.Fatalf("Expected environment main path to be:\n  '%s'\n, got:\n  '%s'", expectedMainPath, mainPath)
 	}
-	if string(envComponentPath) != expectedEnvComponentPath {
-		t.Fatalf("Expected environment component path to be:\n  '%s'\n, got:\n  '%s'", expectedEnvComponentPath, envComponentPath)
+	if string(paramsPath) != expectedParamsPath {
+		t.Fatalf("Expected environment params path to be:\n  '%s'\n, got:\n  '%s'", expectedParamsPath, paramsPath)
 	}
-	if string(envParamsPath) != expectedEnvParamsPath {
-		t.Fatalf("Expected environment params path to be:\n  '%s'\n, got:\n  '%s'", expectedEnvParamsPath, envParamsPath)
+	if string(specPath) != expectedSpecPath {
+		t.Fatalf("Expected environment spec path to be:\n  '%s'\n, got:\n  '%s'", expectedSpecPath, specPath)
 	}
 }
 
diff --git a/prototype/snippet/jsonnet/snippet.go b/prototype/snippet/jsonnet/snippet.go
index ffde16ed3e0ec6f03f2d27fa3b1e5904b0c6c2f5..7324bfb33b0061922e52726768512bfcb503ee0a 100644
--- a/prototype/snippet/jsonnet/snippet.go
+++ b/prototype/snippet/jsonnet/snippet.go
@@ -17,6 +17,7 @@ package jsonnet
 
 import (
 	"errors"
+	"fmt"
 	"sort"
 	"strings"
 
@@ -27,6 +28,9 @@ import (
 const (
 	paramPrefix            = "param://"
 	paramReplacementPrefix = "params."
+
+	envPrefix            = "env://"
+	envReplacementPrefix = "env."
 )
 
 // Parse rewrites the imports in a Jsonnet file before returning the snippet.
@@ -52,14 +56,14 @@ func parse(fn string, jsonnet string) (string, error) {
 
 	var imports []ast.Import
 
-	// Gather all parameter imports
+	// Gather all parameter or environment imports
 	err = visit(root, &imports)
 	if err != nil {
 		return "", err
 	}
 
-	// Replace all parameter imports
-	return replace(jsonnet, imports), nil
+	// Replace all parameter or environment imports
+	return replace(jsonnet, imports)
 }
 
 // ---------------------------------------------------------------------------
@@ -67,11 +71,17 @@ func parse(fn string, jsonnet string) (string, error) {
 func visit(node ast.Node, imports *[]ast.Import) error {
 	switch n := node.(type) {
 	case *ast.Import:
-		// Add parameter-type imports to the list of replacements.
+		// Add parameter/environment type imports to the list of replacements.
 		if strings.HasPrefix(n.File.Value, paramPrefix) {
 			param := strings.TrimPrefix(n.File.Value, paramPrefix)
 			if len(param) < 1 {
-				return errors.New("There must be a parameter following import param://")
+				return fmt.Errorf("There must be a parameter following import %s", paramPrefix)
+			}
+			*imports = append(*imports, *n)
+		} else if strings.HasPrefix(n.File.Value, envPrefix) {
+			env := strings.TrimPrefix(n.File.Value, envPrefix)
+			if len(env) < 1 {
+				return fmt.Errorf("There must be a attribute following import %s", envPrefix)
 			}
 			*imports = append(*imports, *n)
 		}
@@ -297,8 +307,10 @@ func visitLocalBind(node ast.LocalBind, imports *[]ast.Import) error {
 // ---------------------------------------------------------------------------
 
 // replace converts all parameters in the passed Jsonnet of form
-// `import 'param://port'` into `params.port`.
-func replace(jsonnet string, imports []ast.Import) string {
+//
+//   1. `import 'param://port'` into `params.port`.
+//   2. `import 'env://namespace'` into `env.namespace`.
+func replace(jsonnet string, imports []ast.Import) (string, error) {
 	lines := strings.Split(jsonnet, "\n")
 
 	// Imports must be sorted by reverse location to avoid indexing problems
@@ -311,28 +323,35 @@ func replace(jsonnet string, imports []ast.Import) string {
 	})
 
 	for _, im := range imports {
-		param := paramReplacementPrefix + strings.TrimPrefix(im.File.Value, paramPrefix)
+		var replacement string
+		if strings.HasPrefix(im.File.Value, paramPrefix) {
+			replacement = paramReplacementPrefix + strings.TrimPrefix(im.File.Value, paramPrefix)
+		} else if strings.HasPrefix(im.File.Value, envPrefix) {
+			replacement = envReplacementPrefix + strings.TrimPrefix(im.File.Value, envPrefix)
+		} else {
+			return "", fmt.Errorf("Found unsupported import prefix in %s", im.File.Value)
+		}
 
 		lineStart := im.Loc().Begin.Line
 		lineEnd := im.Loc().End.Line
 		colStart := im.Loc().Begin.Column
 		colEnd := im.Loc().End.Column
 
-		// Case where import param is split over multiple strings.
+		// Case where import is split over multiple strings.
 		if lineEnd != lineStart {
 			// Replace all intermediate lines with the empty string.
 			for i := lineStart; i < lineEnd-1; i++ {
 				lines[i] = ""
 			}
-			// Remove import param related logic from the last line.
+			// Remove import related logic from the last line.
 			lines[lineEnd-1] = lines[lineEnd-1][colEnd:len(lines[lineEnd-1])]
-			// Perform replacement in the first line of import param occurance.
-			lines[lineStart-1] = lines[lineStart-1][:colStart-1] + param
+			// Perform replacement in the first line of import occurance.
+			lines[lineStart-1] = lines[lineStart-1][:colStart-1] + replacement
 		} else {
 			line := lines[lineStart-1]
-			lines[lineStart-1] = line[:colStart-1] + param + line[colEnd:len(line)]
+			lines[lineStart-1] = line[:colStart-1] + replacement + line[colEnd:len(line)]
 		}
 	}
 
-	return strings.Join(lines, "\n")
+	return strings.Join(lines, "\n"), nil
 }
diff --git a/prototype/snippet/jsonnet/snippet_test.go b/prototype/snippet/jsonnet/snippet_test.go
index d2f60bbc349df67b2fde5ec6daf0a325f81fef89..e95b066b0dd56bf6402f51c68d8f8c8cc920800c 100644
--- a/prototype/snippet/jsonnet/snippet_test.go
+++ b/prototype/snippet/jsonnet/snippet_test.go
@@ -135,6 +135,32 @@ func TestParse(t *testing.T) {
 			`local f = f;
 			{ foo: f, }`,
 		},
+		// Test where there are multiple import types.
+		{
+			`
+			local k = import 'ksonnet.beta.2/k.libsonnet';
+			
+			local service = k.core.v1.service;
+			local servicePort = k.core.v1.service.mixin.spec.portsType;
+			local port = servicePort.new((import 'param://port'), (import 'param://portName'));
+			
+			local namespace = import 'env://namespace';
+			
+			local name = import 'param://name';
+			k.core.v1.service.new('%s-service' % [name], {app: name}, port)`,
+
+			`
+			local k = import 'ksonnet.beta.2/k.libsonnet';
+			
+			local service = k.core.v1.service;
+			local servicePort = k.core.v1.service.mixin.spec.portsType;
+			local port = servicePort.new((params.port), (params.portName));
+			
+			local namespace = env.namespace;
+			
+			local name = params.name;
+			k.core.v1.service.new('%s-service' % [name], {app: name}, port)`,
+		},
 	}
 
 	errors := []string{