diff --git a/playbooks/javascript/post-tarball.yaml b/playbooks/javascript/post-tarball.yaml
new file mode 100644
index 00000000..92061a54
--- /dev/null
+++ b/playbooks/javascript/post-tarball.yaml
@@ -0,0 +1,4 @@
+- hosts: all
+  roles:
+    - version-from-git
+    - fetch-javascript-tarball
diff --git a/playbooks/javascript/post.yaml b/playbooks/javascript/post.yaml
new file mode 100644
index 00000000..fc32a991
--- /dev/null
+++ b/playbooks/javascript/post.yaml
@@ -0,0 +1,3 @@
+- hosts: all
+  roles:
+    - fetch-javascript-output
diff --git a/playbooks/javascript/pre.yaml b/playbooks/javascript/pre.yaml
new file mode 100644
index 00000000..747029e8
--- /dev/null
+++ b/playbooks/javascript/pre.yaml
@@ -0,0 +1,9 @@
+- hosts: all
+  roles:
+    - role: bindep
+      bindep_profile: test
+      bindep_dir: "{{ zuul_work_dir }}"
+    - test-setup
+    - install-nodejs
+    - revoke-sudo
+    - install-javascript-packages
diff --git a/playbooks/javascript/tarball.yaml b/playbooks/javascript/tarball.yaml
new file mode 100644
index 00000000..79c3f872
--- /dev/null
+++ b/playbooks/javascript/tarball.yaml
@@ -0,0 +1,4 @@
+- hosts: all
+  roles:
+    - role: npm
+      npm_command: pack
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index b1087416..650a62a6 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -351,6 +351,29 @@
     pre-run: playbooks/python-tarball/pre
     run: playbooks/python-tarball/run
 
+- job:
+    name: publish-openstack-javascript-tarball
+    parent: publish-openstack-artifacts
+    description: |
+      Build and publish source tarball for a Javascript project.
+
+      Responds to these variables:
+
+      .. zuul:jobvar:: node_version
+         :default: 6
+
+        The version of Node to use.
+
+      .. zuul:jobvar: zuul_work_dir
+         :default: {{ zuul.project.src_dir }}
+
+        Path to operate in.
+    pre-run: playbooks/javascript/pre
+    run: playbooks/javascript/tarball
+    post-run:
+      - playbooks/javascript/post
+      - playbooks/javascript/post-tarball
+
 - job:
     name: announce-release
     description:
diff --git a/zuul.d/project-templates.yaml b/zuul.d/project-templates.yaml
index 4023654e..da7f9f88 100644
--- a/zuul.d/project-templates.yaml
+++ b/zuul.d/project-templates.yaml
@@ -399,3 +399,33 @@
     release:
       jobs:
         - trigger-readthedocs
+
+- project-template:
+    name: nodejs4-publish-to-npm
+    release:
+      jobs:
+        - publish-openstack-javascript-tarball:
+            vars:
+              node_version: 4
+        - release-openstack-javascript:
+            vars:
+              node_version: 4
+        - announce-release:
+            dependencies:
+              - release-openstack-javascript
+              - publish-openstack-javascript-tarball
+
+- project-template:
+    name: nodejs6-publish-to-npm
+    release:
+      jobs:
+        - publish-openstack-javascript-tarball:
+            vars:
+              node_version: 6
+        - release-openstack-javascript:
+            vars:
+              node_version: 6
+        - announce-release:
+            dependencies:
+              - release-openstack-javascript
+              - publish-openstack-javascript-tarball
diff --git a/zuul.d/zuul-legacy-project-templates.yaml b/zuul.d/zuul-legacy-project-templates.yaml
index a839301a..306a5410 100644
--- a/zuul.d/zuul-legacy-project-templates.yaml
+++ b/zuul.d/zuul-legacy-project-templates.yaml
@@ -976,21 +976,6 @@
         - legacy-nodejs4-npm-run-lint
         - legacy-nodejs4-npm-run-test
 
-- project-template:
-    name: nodejs4-publish-to-npm
-    release:
-      jobs:
-        - publish-openstack-python-tarball:
-            dependencies:
-              - publish-openstack-python-tarball
-        - announce-release:
-            dependencies:
-              - legacy-npm-upload
-        - legacy-npm-upload:
-            dependencies:
-              - publish-openstack-python-tarball
-        - publish-openstack-python-tarball
-
 - project-template:
     name: nodejs6-docs
     check:
@@ -1007,21 +992,6 @@
         - legacy-nodejs6-npm-run-lint
         - legacy-nodejs6-npm-run-test
 
-- project-template:
-    name: nodejs6-publish-to-npm
-    release:
-      jobs:
-        - publish-openstack-python-tarball:
-            dependencies:
-              - publish-openstack-python-tarball
-        - announce-release:
-            dependencies:
-              - legacy-npm-upload
-        - legacy-npm-upload:
-            dependencies:
-              - publish-openstack-python-tarball
-        - publish-openstack-python-tarball
-
 - project-template:
     name: noop-jobs
     check: