diff --git a/pwa-devdocs/src/_config.yml b/pwa-devdocs/src/_config.yml
index 9bb9549bd3..63f79a5f44 100644
--- a/pwa-devdocs/src/_config.yml
+++ b/pwa-devdocs/src/_config.yml
@@ -39,7 +39,11 @@ defaults:
path: "venia-pwa-concept"
values:
toc-group: "venia-pwa-concept"
-
+ -
+ scope:
+ path: "tutorials"
+ values:
+ toc-group: "tutorials"
algolia:
application_id: 'E642SEDTHL'
diff --git a/pwa-devdocs/src/_data/top-nav.yml b/pwa-devdocs/src/_data/top-nav.yml
index 9b46eeab9f..e453d0dbd4 100644
--- a/pwa-devdocs/src/_data/top-nav.yml
+++ b/pwa-devdocs/src/_data/top-nav.yml
@@ -9,3 +9,6 @@
- label: Venia Storefront
url: /venia-pwa-concept/
+
+- label: Tutorials
+ url: /tutorials/
diff --git a/pwa-devdocs/src/_data/tutorials.yml b/pwa-devdocs/src/_data/tutorials.yml
new file mode 100644
index 0000000000..2edf11f5aa
--- /dev/null
+++ b/pwa-devdocs/src/_data/tutorials.yml
@@ -0,0 +1,16 @@
+title: Tutorials
+entries:
+ - label: Overview
+ url: /tutorials/
+
+ - label: Hello UPWARD
+ entries:
+
+ - label: Creating a simple server
+ url: /tutorials/hello-upward/simple-server/
+
+ - label: Using the TemplateResolver
+ url: /tutorials/hello-upward/using-template-resolver/
+
+ - label: Adding React
+ url: /tutorials/hello-upward/adding-react/
diff --git a/pwa-devdocs/src/_includes/layout/sidebar-nav-root-item.html b/pwa-devdocs/src/_includes/layout/sidebar-nav-root-item.html
index 5f54818d35..e807da0901 100644
--- a/pwa-devdocs/src/_includes/layout/sidebar-nav-root-item.html
+++ b/pwa-devdocs/src/_includes/layout/sidebar-nav-root-item.html
@@ -10,6 +10,9 @@
{% elsif page.toc-group == "venia-pwa-concept" %}
{% assign toc = site.data.venia-pwa-concept %}
+{% elsif page.toc-group == "tutorials" %}
+ {% assign toc = site.data.tutorials %}
+
{% endif %}
-{% include layout/toc.html %}
\ No newline at end of file
+{% include layout/toc.html %}
diff --git a/pwa-devdocs/src/_scss/main.scss b/pwa-devdocs/src/_scss/main.scss
index ac95e7672d..dc5a013495 100644
--- a/pwa-devdocs/src/_scss/main.scss
+++ b/pwa-devdocs/src/_scss/main.scss
@@ -8,3 +8,4 @@
@import "src/material-icons";
@import "src/site-header-overrides.scss";
+@import "src/code-block-style-overrides.scss";
diff --git a/pwa-devdocs/src/_scss/src/_code-block-style-overrides.scss b/pwa-devdocs/src/_scss/src/_code-block-style-overrides.scss
new file mode 100644
index 0000000000..af523ee1b9
--- /dev/null
+++ b/pwa-devdocs/src/_scss/src/_code-block-style-overrides.scss
@@ -0,0 +1,13 @@
+.highlight .gd,
+.highlight .gi {
+ border: none;
+ background: none;
+}
+
+.highlight .gi {
+ color: #00B218;
+}
+
+.highlight .gd {
+ color: #FF3B6F;
+}
diff --git a/pwa-devdocs/src/tutorials/hello-upward/adding-react/index.md b/pwa-devdocs/src/tutorials/hello-upward/adding-react/index.md
new file mode 100644
index 0000000000..c1cea29bbb
--- /dev/null
+++ b/pwa-devdocs/src/tutorials/hello-upward/adding-react/index.md
@@ -0,0 +1,176 @@
+---
+title: Adding React
+---
+
+This tutorial teaches you how to add webpack to your UPWARD project and use it to create a React application.
+
+This tutorial builds on the project described in the previous [Using the TemplateResolver][] topic.
+
+## Install dependencies
+
+Add babel, webpack, and react dependencies to the project:
+
+```sh
+yarn add @babel/core @babel/preset-env babel-loader webpack webpack-cli @babel/preset-react react react-dom
+```
+
+In addition to installing React, this command installs [babel][] configurations and [webpack][].
+
+In general, React components are written using ES6([ECMAScript 2015][]) and [JSX][] syntax for the convenience and ease of readability they provide.
+Using [babel][] and [webpack][] is a common way to incorporate ES6 and JSX into a React project.
+
+## Modify template
+
+Modify the `hello-world.mst` template to replace the original message with a "root" DOM node for the React application:
+
+{% raw %}
+
+```diff
+{{> templates/open-document}}
+
+
{{ title }}
+
+ {{> templates/open-body}}
+
+- Hello Template World!
++ Loading...
++
++
+
+ {{> templates/close-document}}
+```
+
+{% endraw %}
+
+This update renders a loading message in the root DOM and executes the `app.js` script after the browser parses the HTML document.
+
+## Create webpack config
+
+Create a `webpack.config.js` file to configure webpack behavior:
+
+```js
+const path = require('path');
+
+module.exports = {
+ mode: 'development',
+ entry: './src/hello-world.js',
+ output: {
+ filename: 'app.js',
+ path: path.resolve(__dirname, 'dist')
+ },
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader'
+ }
+ ]
+ }
+};
+```
+
+This configuration file tells webpack to transpile all JavaScript files using babel and bundle `src/hello-world.js` with its dependencies into `dist/app.js`.
+
+## Create babel config
+
+Create a `.babelrc` file to configure babel:
+
+```text
+{
+ "presets": ["@babel/preset-env","@babel/preset-react"]
+}
+```
+
+This configuration file tells babel what presets to use during JavaScript transpilation.
+The presets used in this example, `@babel/preset-env` and `@babel/preset-react`, are common React development presets.
+
+## Create the React application
+
+Create a `src` directory in your project's root directory and a `hello-world.js` file inside that directory with the following content:
+
+```jsx
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+class App extends React.Component {
+ render() {
+ return Hello React World!
;
+ }
+}
+
+ReactDOM.render(, document.getElementById('root'));
+```
+
+This file defines an `App` React component that returns a "Hello React World!" message wrapped inside `h1` tags.
+It uses the `ReactDOM` module to inject the content of the application into the "root" DOM element in the document.
+
+## Make the application script publicly available
+
+Edit the `spec.yml` file to add a new URL pattern to check in the ConditionalResolver and a new `appScript` object.
+
+```diff
+...
+
+response:
+ resolver: conditional
+ when:
+ - matches: request.url.pathname
+ pattern: '^/?$'
+ use: helloWorld
+ - matches: request.url.pathname
+ pattern: '^/hello-world/?$'
+ use: helloWorld
++ - matches: request.url.pathname
++ pattern: '^/js/app.js'
++ use: appScript
+ default: notFound
+
+helloWorld:
+...
+
+notFound:
+...
+
++ appScript:
++ inline:
++ status:
++ resolver: inline
++ inline: 200
++ headers:
++ resolver: inline
++ inline:
++ content-type:
++ resolver: inline
++ inline: 'application/javascript'
++ body:
++ resolver: file
++ file:
++ resolver: inline
++ inline: './dist/app.js'
++ encoding:
++ resolver: inline
++ inline: 'utf-8'
+```
+
+This update uses a [FileResolver][] which instructs the UPWARD server to respond with the contents of `dist/app.js` when there is a request for the `js/app.js` path.
+
+## Create the bundle and start the server
+
+Create the `dist/app.js` bundle from `src/hello-world.js` and start the UPWARD server:
+
+```sh
+npx webpack && node server.js
+```
+
+When webpack bundles `src/hello-world.js` into `dist/app.js`, it includes its dependencies, such as React and ReactDOM.
+
+When you navigate to the server, you will see the React application render the "Hello React World!" message using the App component.
+
+[Using the TemplateResolver]: {{site.baseurl}}{%link tutorials/hello-upward/using-template-resolver/index.md %}
+
+[ecmascript 2015]: http://www.ecma-international.org/ecma-262/6.0/index.html
+[jsx]: https://reactjs.org/docs/introducing-jsx.html
+[babel]: https://babeljs.io/
+[webpack]: https://webpack.js.org/
+[FileResolver]: https://github.com/magento-research/pwa-studio/tree/develop/packages/upward-spec#fileresolver
diff --git a/pwa-devdocs/src/tutorials/hello-upward/simple-server/index.md b/pwa-devdocs/src/tutorials/hello-upward/simple-server/index.md
new file mode 100644
index 0000000000..f59a66b36a
--- /dev/null
+++ b/pwa-devdocs/src/tutorials/hello-upward/simple-server/index.md
@@ -0,0 +1,214 @@
+---
+title: Creating a simple server
+---
+
+This tutorial teaches the basics of reading and writing an UPWARD specification file by creating a simple web server that returns a "Hello World" string.
+
+## Prerequisites
+
+- [Node][] >= 10.14.1
+- [Yarn][] (recommended) or [NPM][]
+
+## Initial setup
+
+1. Create the project directory and navigate into it:
+
+ ```sh
+ mkdir hello-upward && cd hello-upward
+ ```
+
+1. Use Yarn or NPM to initialize the project's `package.json` file:
+
+ ```sh
+ yarn init -y
+ ```
+
+ Running this command creates a `package.json` file in your current directory.
+ The `package.json` file contains information about your project, such as name, version, dependencies, and runnable commands.
+
+ The `-y` parameter is used in this tutorial to skip the interactive session.
+ Omit this parameter if you want to fill out information about your project during initialization.
+
+1. Install the `@magento/upward-js` and `express` packages:
+
+ ```sh
+ yarn add @magento/upward-js express
+ ```
+
+ The [`upward-js`][] package contains modules for deploying an UPWARD-compliant server.
+
+ [Express][] is a web framework for Node.js.
+ It is a dependency for the `upward-js` modules used in this tutorial.
+
+## Create the initial UPWARD spec
+
+An UPWARD server requires an [UPWARD specification][] file to tell it how to respond to requests.
+Create a new file called `spec.yml` with the following content:
+
+```yml
+status: response.status
+headers: response.headers
+body: response.body
+
+response:
+ resolver: inline
+ inline:
+ status:
+ resolver: inline
+ inline: 200
+ headers:
+ resolver: inline
+ inline:
+ content-type:
+ resolver: inline
+ inline: 'text/string'
+ body:
+ resolver: inline
+ inline: 'Hello World!'
+```
+
+The first three lines set the `status`, `headers`, and `body` values required for an UPWARD server response.
+These values are set by traversing a decision tree defined in the specification file.
+
+In this example, they are set to the `response.status`, `response.headers`, and `response.body` values defined in the `response` object.
+These values are set using an UPWARD [InlineResolver][], which resolves the value of the `inline` property to a literal value.
+
+When passed to an UPWARD server, this file instructs the server to respond with a `200 OK` status code, content of type `text/string`, and a value of `Hello World!` in the response body for every request.
+
+## Create and run the server
+
+Create a `server.js` file with logic for starting the Node implementation of an UPWARD server.
+
+```js
+const { createUpwardServer } = require('@magento/upward-js');
+
+createUpwardServer({
+ upwardPath: 'spec.yml',
+ bindLocal: true,
+ logUrl: true,
+ port: 8080
+});
+```
+
+This file imports the `createUpwardServer` module from the `@magento/upward-js` package and uses it to start a web server.
+
+The script specifies the location of the UPWARD specification file through the `upwardPath` configuration and sets the port number of the server to `8080`.
+The `logUrl` configuration tells the script to display the URL of the server and `bindLocal` tells it to create and bind to local HTTP server.
+
+Use `node` to run the server script:
+
+```sh
+node server.js
+```
+
+When the server starts, the URL for the server is displayed in the terminal.
+
+```sh
+> node server.js
+
+http://0.0.0.0:8080/
+```
+
+Navigate to this URL in your browser to see the "Hello World!" message.
+
+## Define a 404 response
+
+When you browse to the server, every path request returns the same message.
+To restrict this message to a specific path, use a ConditionalResolver.
+
+Edit `spec.yml` and replace the InlineResolver content of the `response` object with a [ConditionalResolver][] to define which paths return "Hello World!".
+
+```diff
+status: response.status
+headers: response.headers
+body: response.body
+
+response:
+- resolver: inline
+- inline:
+- status:
+- resolver: inline
+- inline: 200
+- headers:
+- resolver: inline
+- inline:
+- content-type:
+- resolver: inline
+- inline: 'text/string'
+- body:
+- resolver: inline
+- inline: 'Hello World!'
++ resolver: conditional
++ when:
++ - matches: request.url.pathname
++ pattern: '^/?$'
++ use: helloWorld
++ - matches: request.url.pathname
++ pattern: '^/hello-world/?$'
++ use: helloWorld
++ default: notFound
+```
+
+This code tells the server to look at the requested URL path and check to see if it matches the root or `/hello-world` path.
+If it matches, the server uses an object called `helloWorld` to resolve the response.
+For all other paths, the server resolves the response using the `notFound` object.
+
+After the `response` object, define the following `helloWorld` and `notFound` objects in the `spec.yml` file:
+
+```yml
+helloWorld:
+ inline:
+ status:
+ resolver: inline
+ inline: 200
+ headers:
+ resolver: inline
+ inline:
+ content-type:
+ resolver: inline
+ inline: 'text/string'
+ body:
+ resolver: inline
+ inline: 'Hello World!'
+
+notFound:
+ inline:
+ status:
+ resolver: inline
+ inline: 404
+ headers:
+ resolver: inline
+ inline:
+ content-type:
+ resolver: inline
+ inline: 'text/string'
+ body:
+ resolver: inline
+ inline: 'Page not found!'
+```
+
+Now, when you start the server and navigate to the application, only the root and `/hello-world` path return the "Hello World!" message.
+All other paths return the `404` response.
+
+Valid URLS:
+
+* `http://0.0.0.0:8080/`
+* `http://0.0.0.0:8080/hello-world`
+
+Examples of invalid URLS:
+
+* `http://0.0.0.0:8080/goodbye-world`
+* `http://0.0.0.0:8080/something-else`
+
+**Next:** [Rendering web pages using the TemplateResolver][]
+
+[upward specification]: https://github.com/magento-research/pwa-studio/tree/master/packages/upward-spec
+[node]: https://nodejs.org
+[yarn]: https://yarnpkg.com/en/
+[npm]: https://www.npmjs.com/get-npm
+[express]: https://expressjs.com/
+
+[`upward-js`]: {{site.baseurl}}{% link technologies/upward/reference-implementation/index.md %}
+[Rendering web pages using the TemplateResolver]: {{site.baseurl}}{% link tutorials/hello-upward/using-template-resolver/index.md %}
+[InlineResolver]: https://github.com/magento-research/pwa-studio/tree/develop/packages/upward-spec#inlineresolver
+[ConditionalResolver]: https://github.com/magento-research/pwa-studio/tree/develop/packages/upward-spec#conditionalresolver
diff --git a/pwa-devdocs/src/tutorials/hello-upward/using-template-resolver/index.md b/pwa-devdocs/src/tutorials/hello-upward/using-template-resolver/index.md
new file mode 100644
index 0000000000..cb890f6f5b
--- /dev/null
+++ b/pwa-devdocs/src/tutorials/hello-upward/using-template-resolver/index.md
@@ -0,0 +1,107 @@
+---
+title: Using the TemplateResolver
+---
+
+In this tutorial, you will learn how to use the [TemplateResolver][] in your UPWARD specification file to serve an HTML page rendered server-side.
+
+This tutorial builds on the project described in the previous [Creating a simple server][] tutorial.
+
+## Create web page templates
+
+In your project directory, create a `templates` directory. This directory will house [Mustache][] template files for the different pieces of the HTML page.
+
+**`open-document.mst`**
+
+```mustache
+
+
+
+
+
+```
+
+This template partial creates the beginning of the HTML response.
+The `head` tag is left open to allow custom metadata, such as title, scripts, and styles.
+
+**`open-body.mst`**
+
+```mustache
+
+
+```
+
+This template partial closes the `head` tag and begins the `body` tag of the HTML response.
+
+**`close-document.mst`**
+
+```mustache
+
+
+```
+
+This template partial closes the `body` and `html` tag for the HTML response.
+
+**`hello-world.mst`**
+
+{% raw %}
+
+```mustache
+{{> templates/open-document}}
+
+ {{ title }}
+
+ {{> templates/open-body}}
+
+ Hello Template World!
+
+ {{> templates/close-document}}
+```
+
+{% endraw %}
+
+This template uses the previously defined template partials to create a complete HTML response.
+The body contains the "Hello Template World!" message in bold and sets the page title to a `title` variable, which is available through the template context.
+
+## Add TemplateResolver
+
+Modify the `helloWorld` object in the `spec.yml` file and replace the simple text response to an actual HTML page.
+
+```diff
+helloWorld:
+ inline:
+ status:
+ resolver: inline
+ inline: 200
+ headers:
+ resolver: inline
+ inline:
+ content-type:
+ resolver: inline
+- inline: 'text/string'
++ inline: 'text/html'
+ body:
+- resolver: inline
+- inline: 'Hello World!'
++ resolver: template
++ engine: mustache
++ template: './templates/hello-world.mst'
++ provide:
++ title:
++ resolver: inline
++ inline: 'This is the page title!'
+```
+
+This new code replaces the InlineResolver with a TemplateResolver in the response body.
+This TemplateResolver configuration sets the rendering engine to `mustache`, since the templates created previously are in Mustache format.
+It also provides the `title` variable to the context during template render.
+
+Now, when you start the server and navigate to the root or `/hello-world` path, you get an actual HTML webpage instead of text.
+View the page source for the page to see the HTML rendered from the templates.
+
+**Next:** [Adding React to the server][]
+
+[Creating a simple server]: {{site.baseurl}}{%link tutorials/hello-upward/simple-server/index.md %}
+[Adding React to the server]: {{site.baseurl}}{%link tutorials/hello-upward/adding-react/index.md %}
+
+[Mustache]: https://mustache.github.io/mustache.5.html
+[TemplateResolver]: https://github.com/magento-research/pwa-studio/tree/develop/packages/upward-spec#templateresolver
diff --git a/pwa-devdocs/src/tutorials/index.md b/pwa-devdocs/src/tutorials/index.md
index d584fbf875..8f6c980ca4 100644
--- a/pwa-devdocs/src/tutorials/index.md
+++ b/pwa-devdocs/src/tutorials/index.md
@@ -1,5 +1,5 @@
---
-title:
+title: Tutorials
---
-{% include content-not-available.md %}
\ No newline at end of file
+This section contains tutorials that will help you become familiar with the different tools provided by PWA Studio.