diff --git a/cmd/helm/install.go b/cmd/helm/install.go
index e80527b48949860d1580c201624a88d9fdd9cfcc..e71a3ed41213ab1aa2c85d3ac9e6356724c0f55f 100644
--- a/cmd/helm/install.go
+++ b/cmd/helm/install.go
@@ -17,6 +17,7 @@ limitations under the License.
 package main
 
 import (
+	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -24,6 +25,9 @@ import (
 	"path/filepath"
 	"strings"
 
+	"html/template"
+
+	"github.com/Masterminds/sprig"
 	"github.com/ghodss/yaml"
 	"github.com/spf13/cobra"
 
@@ -63,6 +67,7 @@ type installCmd struct {
 	out          io.Writer
 	client       helm.Interface
 	values       *values
+	nameTemplate string
 }
 
 func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
@@ -100,6 +105,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
 	f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install")
 	f.BoolVar(&inst.reuseName, "reuse-name", false, "force Tiller to re-use the given name, even if that name is already used. This is unsafe in production")
 	f.Var(inst.values, "set", "set values on the command line. Separate values with commas: key1=val1,key2=val2")
+	f.StringVar(&inst.nameTemplate, "name-template", "", "specify template used to name the release")
 	return cmd
 }
 
@@ -113,6 +119,16 @@ func (i *installCmd) run() error {
 		return err
 	}
 
+	// If template is specified, try to run the template.
+	if i.nameTemplate != "" {
+		i.name, err = generateName(i.nameTemplate)
+		if err != nil {
+			return err
+		}
+		// Print the final name so the user knows what the final name of the release is.
+		fmt.Printf("final name: %s\n", i.name)
+	}
+
 	res, err := i.client.InstallRelease(
 		i.chartPath,
 		i.namespace,
@@ -249,3 +265,16 @@ func locateChartPath(name string) (string, error) {
 
 	return name, fmt.Errorf("file %q not found", origname)
 }
+
+func generateName(nameTemplate string) (string, error) {
+	t, err := template.New("name-template").Funcs(sprig.FuncMap()).Parse(nameTemplate)
+	if err != nil {
+		return "", err
+	}
+	var b bytes.Buffer
+	err = t.Execute(&b, nil)
+	if err != nil {
+		return "", err
+	}
+	return b.String(), nil
+}
diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go
index 41663a337c8a52e4979eae336d7f0c82a755b133..24b05df4d71990c0e79c9604817ad4ac2cfd0962 100644
--- a/cmd/helm/install_test.go
+++ b/cmd/helm/install_test.go
@@ -19,6 +19,7 @@ package main
 import (
 	"fmt"
 	"io"
+	"regexp"
 	"strings"
 	"testing"
 
@@ -65,6 +66,14 @@ func TestInstall(t *testing.T) {
 			expected: "aeneas",
 			resp:     releaseMock(&releaseOptions{name: "aeneas"}),
 		},
+		// Install, using the name-template
+		{
+			name:     "install with name-template",
+			args:     []string{"testdata/testcharts/alpine"},
+			flags:    []string{"--name-template", "{{upper \"foobar\"}}"},
+			expected: "FOOBAR",
+			resp:     releaseMock(&releaseOptions{name: "FOOBAR"}),
+		},
 	}
 
 	runReleaseCases(t, tests, func(c *fakeReleaseClient, out io.Writer) *cobra.Command {
@@ -113,3 +122,78 @@ sailor: sinbad
 		t.Errorf("Expected String() to be \n%s\nGot\n%s\n", y, out)
 	}
 }
+
+type nameTemplateTestCase struct {
+	tpl              string
+	expected         string
+	expectedErrorStr string
+}
+
+func TestNameTemplate(t *testing.T) {
+	testCases := []nameTemplateTestCase{
+		// Just a straight up nop please
+		{
+			tpl:              "foobar",
+			expected:         "foobar",
+			expectedErrorStr: "",
+		},
+		// Random numbers at the end for fun & profit
+		{
+			tpl:              "foobar-{{randNumeric 6}}",
+			expected:         "foobar-[0-9]{6}$",
+			expectedErrorStr: "",
+		},
+		// Random numbers in the middle for fun & profit
+		{
+			tpl:              "foobar-{{randNumeric 4}}-baz",
+			expected:         "foobar-[0-9]{4}-baz$",
+			expectedErrorStr: "",
+		},
+		// No such function
+		{
+			tpl:              "foobar-{{randInt}}",
+			expected:         "",
+			expectedErrorStr: "function \"randInt\" not defined",
+		},
+		// Invalid template
+		{
+			tpl:              "foobar-{{",
+			expected:         "",
+			expectedErrorStr: "unexpected unclosed action",
+		},
+	}
+
+	for _, tc := range testCases {
+
+		n, err := generateName(tc.tpl)
+		if err != nil {
+			if tc.expectedErrorStr == "" {
+				t.Errorf("Was not expecting error, but got: %v", err)
+				continue
+			}
+			re, compErr := regexp.Compile(tc.expectedErrorStr)
+			if compErr != nil {
+				t.Errorf("Expected error string failed to compile: %v", compErr)
+				continue
+			}
+			if !re.MatchString(err.Error()) {
+				t.Errorf("Error didn't match for %s expected %s but got %v", tc.tpl, tc.expectedErrorStr, err)
+				continue
+			}
+		}
+		if err == nil && tc.expectedErrorStr != "" {
+			t.Errorf("Was expecting error %s but didn't get an error back", tc.expectedErrorStr)
+		}
+
+		if tc.expected != "" {
+			re, err := regexp.Compile(tc.expected)
+			if err != nil {
+				t.Errorf("Expected string failed to compile: %v", err)
+				continue
+			}
+			if !re.MatchString(n) {
+				t.Errorf("Returned name didn't match for %s expected %s but got %s", tc.tpl, tc.expected, n)
+			}
+		}
+	}
+}