Self-hosted service
ampproject/amp.dev avatar
ampproject/amp.dev

amp.dev runs on Grow, Gulp and a lot of side applications

The AMP Project Website.

600 stars675 forksHTMLNOASSERTION

At a glance

What is it?
The amp.dev repository is the AMP Project website, and it is not a single site: it is a Python-based Grow static site, an Express backend, a Playground, a Boilerplate generator and several frontends wired together through Gulp. Getting it running means Python, Node, a GitHub token and a local import of the docs, and Windows is explicitly unsupported.
Who is it for?
amp.dev is worth setting up if you plan to contribute documentation, samples or frontend work to the AMP Project, since the import step and the Playground are the only way to see the site as it will be published. It is not the right place to start if you only want to read AMP documentation, and it is a poor fit on Windows, where the README states there is no support.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One website, several applications in the same tree

amp.dev is described as the official homepage of the AMP Project, but the repository is not a single static site. It is a collection of applications that a contributor has to run together.

The directories give the map. pages/ holds the site content, which the README refers to as markdown files in pages/content. platform/ contains the Express backend and a serve.js entry point, and the package.json scripts start it with NODE_ENV set to local, staging or production. playground/ is the AMP Playground with its own webpack build. boilerplate/ has a build.js for the code generator, and pixi/ and frontend21/ are separate webpack bundles, with frontend/ alongside them. There are also netlify/, thumbor/, packager/, templates/, smoke-tests/, tests/, examples/ and scripts/ directories, and an app.yaml at the root for App Engine deployment.

The result is a site with several runnable surfaces: a content pipeline, a server, a live playground, a boilerplate generator and multiple frontends. A contributor touches one or two of them, but the toolchain builds all of them together, which is why the setup instructions are as long as they are.

The repository also carries the housekeeping files you would expect from a project with many contributors: an .editorconfig, .eslintrc.json, .prettierrc, a husky directory, renovate.json for dependency updates, and CODE_OF_CONDUCT.md.

Grow does the page rendering, Gulp does the orchestration

The static site generator is Grow, and the README insists you install it with pip rather than its own installer, because installing with pip is what lets you import from the grow package in Python later on. Grow 1 depends on Python 3, so the pip command you use has to be the one attached to Python 3.

The macOS and Linux recipes are nearly identical, and both install pyyaml with the libyaml option so that YAML parsing is faster:

bash
 $ pip3 install --global-option="--with-libyaml" --force pyyaml
 $ pip3 install --user grow

On Linux the README additionally suggests installing the system YAML packages, python-yaml and libyaml-dev, through apt. On macOS the equivalent step installs Homebrew's python and libyaml packages first, and the README notes that Xcode 10.3 or a recent stable version is required for brew doctor to pass.

Around Grow sits the Node toolchain. The root package.json declares node 22.x in its engines field and defines build, start and test scripts that all go through Gulp: build:local, build:staging, build:prod and build:grow-tests map onto gulp build with different environments, while lint runs gulp lintAll. The frontend bundles bypass Gulp for their webpack step but are invoked from the same scripts.

So the build has two halves: Gulp orchestrates, and each artefact is produced by the tool that fits it, webpack for the JavaScript bundles and a node build.js for the boilerplate generator.

Getting the content in requires a GitHub token and a bootstrap run

The site pulls its documentation from GitHub rather than storing it in the repository, and that is why the setup has a token step.

After forking and cloning the repository and installing the Node dependencies, the next step is a bootstrap. The README asks you to set up a valid GitHub access token in an environment variable named AMP_DOC_TOKEN:

bash
$ export AMP_DOC_TOKEN="c59f6..."

The bootstrap command then runs the import from GitHub and, according to the README, builds the Playground and the Boilerplate Generator at the same time:

bash
$ npm run bootstrap

The import is the fragile part of the setup. The README warns that bad network conditions or GitHub API rate limiting can produce errors during the import, and it recommends retrying with the -- --queue-imports flag to avoid them. In other words, a first run against a large documentation set can fail for reasons that have nothing to do with your code.

Fork and clone come first, in the usual order:

bash
$ git clone https://github.com/YOUR-USERNAME/amp.dev
$ cd amp.dev
$ npm install

Contributions go back through a pull request, and the README separates them into three tracks: bug reports and feature requests for the site go to a separate docs issue tracker, documentation and guides have their own contributing guide, and code samples and demos have another. It also notes that fixing spelling mistakes is often easiest by editing the file directly on GitHub.

The develop task watches files and splits work across two ports

Development runs through one npm script:

bash
$ npm run develop

The task builds and copies files, watches them for changes and rebuilds when needed. The README sets the expectation for the output: it prints a lot to the shell and will most likely end on Server ready. Press ctrl-c to quit. Seeing that line means things went fine so far unless the logs say otherwise.

Two ports are involved, and the distinction matters when something looks broken. The site itself is served on port 8080 at http://localhost:8080/, while the service on port 8081 is only Grow rendering the pages. So a failure on 8081 is a content pipeline problem, not a serving problem.

One restart rule is called out: changes to the Express backend require the Gulp task to be restarted. The watch covers static content, not the server process, so a backend edit that appears to do nothing usually means the watcher is still running against the old code.

Maintenance tasks sit alongside. npm run lint:grow is for the case where you changed a lot of Grow documents and are no longer sure whether the references still hold, and the package.json carries a set of Jest configurations, including a separate smoke-test script and per-area test scripts for the platform and the playground.

The Docker route removes Python, not the token

The README acknowledges that a working Python 3 environment can be hard to get going and offers a container as the way around it. The Dockerfile builds on node:22-alpine and installs Python 3 as part of the image, so you can skip setting up Python and installing Grow locally.

What it does not remove is the rest of the setup. You still have to clone the repository, install the Node dependencies and export a valid GitHub token, because the import step still runs. Only the interpreter and Grow move into the image.

Two Gulp tasks drive the container workflow. The first builds the image:

bash
$ npx gulp developImageBuild

The second starts a container from it:

bash
$ npx gulp developContainer

The developContainer task also mounts the pages directory, so edits to any markdown file in pages/content show up in the container without rebuilding the image. That is the main argument for the container route during a documentation-heavy change, since the rebuild cycle is the slow part.

The image itself is small in intent. The Dockerfile starts from node:22-alpine, adds a build toolchain including g++, gcc, make, linux-headers, vips-dev and python3, installs tini as the entrypoint, copies the source and runs npm ci. It exposes port 80 and port 8080 and leaves the command as a shell, since the container is normally driven through the Gulp tasks rather than a single long-running process.

Where this setup will frustrate you

Three practical limits are worth naming before you commit an afternoon to it.

The first is the operating system. The README states that for anyone doing more than fixing typos, Linux and macOS are the only currently supported operating systems and that Windows is not supported at this time. The Docker option does not change that statement, since the Docker workflow assumes the same git, Node and npm steps run on your machine.

The second is that the documentation in the README has drifted from the project configuration. The prose asks for the LTS version of Node.js and, on macOS, says Python 3.7 is required at latest, while the package.json engines field declares node 22.x and the Dockerfile builds on node:22-alpine. The prose also describes the project as the amp.dev website while the package.json repository field points at a different repository name. If you follow the README literally you will install more than you need and possibly the wrong major version.

The third is the token dependency. AMP_DOC_TOKEN is not optional for the documented workflow, the import hits the GitHub API, and rate limiting can break the bootstrap for reasons unrelated to your environment. A shared token across a team, or an unauthenticated fallback, is where this setup starts to fail in ways that look like your own bugs.

Finally, remember what this repository is. It is the website for a documentation project, not the AMP runtime, so a change here affects publishing rather than page performance in an application that embeds AMP.

Deployment targets show how many environments this thing has

The scripts in package.json describe a deployment pipeline with three environments, and the presence of a pixel service and a Netlify directory explains why the build is not a single bundle.

There is build:local, build:staging and build:prod, each a gulp build with a different environment argument, plus build:grow-tests for a test environment. The start scripts mirror them, with start:local running the platform server under NODE_ENV=local and start running it under NODE_ENV=production. Staging logs are read with gcloud app logs tail -s default --project amp-dev-staging, which tells you the site is hosted on Google App Engine, consistent with the app.yaml file at the root.

The frontend and the other bundles are built separately: build:boilerplate runs a node build.js inside boilerplate, and build:playground, build:pixi and build:frontend each run webpack in production mode in their own directory. The start scripts for those use webpack serve in development mode instead, which is why the develop task can show you a live playground while the site renders from Grow.

Maintenance is handled by tooling rather than by hand. renovate.json is present for dependency updates, husky is installed by a postinstall script, and the lint and fix scripts run eslint over the JavaScript. Two encrypted key files,.prod.key.json.enc and.staging.key.json.enc, sit at the root, which indicates that deployment credentials are handled as encrypted artefacts in the repository rather than as committed plaintext.

The repository publishes no GitHub releases, and the last push was on 2026-10-22, so for a contributor the pull request workflow in the README is the whole lifecycle.

Editorial conclusion

amp.dev is worth setting up if you plan to contribute documentation, samples or frontend work to the AMP Project, since the import step and the Playground are the only way to see the site as it will be published. It is not the right place to start if you only want to read AMP documentation, and it is a poor fit on Windows, where the README states there is no support. Before you clone, decide whether you need the Python and Grow toolchain at all or whether the Docker path suits you better, and note that the README still points at Python 3.7 and an LTS Node install while package.json declares node 22.x, so trust the engines field over the prose. The last push was on 2026-10-22.

Frequently asked questions

How do I set up amp.dev for local development?

Install the LTS version of Node.js and Python 3 with pip, install Grow with pip, fork and clone the repository, run npm install, export a GitHub token as AMP_DOC_TOKEN, then run npm run bootstrap followed by npm run develop. The site is then served at http://localhost:8080/.

What does the bootstrap command do in amp.dev?

The README says running npm run bootstrap runs the import from GitHub and also builds the Playground and the Boilerplate Generator. It requires a valid GitHub access token in the AMP_DOC_TOKEN environment variable, and the README recommends the -- --queue-imports flag if bad network conditions or GitHub API rate limiting cause errors.

Can I develop amp.dev on Windows?

No. The README states that for development beyond fixing typos, Linux and macOS are the only currently supported operating systems, and that Windows is not supported at this time. The Docker setup skips the Python and Grow installation but still assumes the Node and git steps run on your machine.

Which ports are used when running the amp.dev develop task?

The site is available at http://localhost:8080/, and the service on port 8081 is only Grow rendering the pages. The README also warns that changes to the Express backend require the Gulp task to be restarted.

Official sources

  1. ampproject/amp.dev on GitHub
  2. Issues
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ampproject-amp-dev.svg)](https://hysenlabs.com/projects/ampproject-amp-dev)

Was this useful?