The difference in Time to Interactivity (TTI) (measure of how long before the user can actually interact with the page e.g. click on a link) between the sites is just as dramatic. Gatsbygram’s TTI is 6.1s vs 14.1s for Instagram.

Gatsby is built for the next billion internet users

As Benedict Evans has noted, the next billion people poised to come online will be using the internet almost exclusively through smartphones.

Smartphones with decent specs (as good or better than the Moto G4), a great browser, but without a reliable internet connection.

Gatsby uses modern web performance ideas (e.g. PRPL) developed by the Google Chrome Developer Relations team and others to help websites work well on modern browsers with unreliable networks.

Sites built with Gatsby run as much as possible in the client so regardless of the network conditions—good, bad, or nonexistent—things will keep working.

Many of the top e-commerce websites in areas where people are coming online for the first time are developing their websites using these techniques.

Read Google’s case studies on:

Gatsby is simple

Modern JavaScript websites are too complex to rely on developers always configuring things correctly. Gatsby simplifies website development by extracting configuration out of your site and moving it into the framework and community plugins.

You give Gatsby React.js components, data, and styles and Gatsby gives you back an optimized website.

Gatsbygram is a completely vanilla Gatsby site. Its optimizations are from the framework.

Gatsby includes a full modern JavaScript toolchain (Babel/webpack/Uglify) with optimized production builds and an innovative declarative asset pipeline.

For Gatsbygram, Gatsby generates over 1000 image thumbnails for responsive images without any custom scripting by leveraging the Gatsby image processing plugin gatsby-transformer-sharp.

Stop wasting time and build something!

App structure

All static site generators create a set of files that determine the routing in your site. Typically, you define the output file structure (and thus URL structure) of your site by way of the input structure. For example the input structure:

my-site/ index. md blogs/ blog1. md

…would be transformed to:

my-site/ index .html blogs/ blog1.html

This is fine at first, but can be limiting. For example, in Gatsbygram, we have a JSON data blob scraped from an Instagram user profile. From this we want to generate a page for each image. We couldn’t do this with a typical static site generator, but Gatsby lets you define routes programmatically through the createPages API using any data you have available.

Here is how we define pages from our JSON data for Gatsbygram at build time in the site’s gatsby-node.js file:

const path = require ( `path` ) const slug = require ( `slug` ) const { slash } = require ( `gatsby-core-utils` ) exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions const result = await graphql( ` { allPostsJson(limit: 1000) { edges { node { id } } } } ` ) if (result.errors) { reporter.panicOnBuild( `Error while running GraphQL query.` ) return } const postTemplate = path.resolve( `src/templates/post-page.js` ) result.data.allPostsJson.edges.forEach( edge => { createPage({ path: `/ ${slug(edge.node.id)} /` , component : slash(postTemplate), context : { id : edge.node.id } }) }) }

Using templates

Gatsby uses standard React.js components to render pages. When you define a page in the createPages API, you specify its component. Those components, usually called templates, get reused with page-specific data to generate the different pages.

As you can see above, when defining a page, we can set “context” data, which is passed as a prop to the component and as a GraphQL variable in our GraphQL query. For the “post template“, we pass the id to the post. Below we use that id to query our GraphQL schema and return a fully formed page:

import React from "react" import PostDetail from "../components/post-detail" class PostTemplate extends React . Component { render() { return ( // PostDetail is used for this detail page and // also in the modal. <PostDetail post={ this .props.data.posts} /> ) } } export default PostTemplate // The post template's GraphQL query. Notice the “id” // variable which is passed in . We set this on the page // context in gatsby-node.js. // // All GraphQL queries in Gatsby are run at build-time and // loaded as plain JSON files so have minimal client cost. export const pageQuery = ` query PostPage($id: String!) { posts(id: { eq: $id }) { username avatar likes id text weeksAgo: time(difference: "weeks" ) image { children { ... on ImageSharp { big: fluid(maxWidth: 640 ) { src srcSet } } } } } } `

Creating React.js component pages

In addition to creating pages for our Instagram photos, we want to make an index page for browsing all photos. To build this index page, Gatsby lets us create pages using React.js components.

pages/ index .js about.js

These React component pages can query the Gatsbygram GraphQL schema for data and are automatically converted into their own pages at gatsbygram.gatsbyjs.org/ and gatsbygram.gatsbyjs.org/about/ .

Gatsbygram’s about.js is a plain React component with no query. index.js is more complex. It queries for thumbnails for all images and has an infinite scroll implementation to lazy load in image thumbnails.

Read pages/index.js on GitHub Read pages/about.js on GitHub

The Layout Component

Each Gatsby site has a top-level layout component at layouts/index.js . This layout component is used on every page of your site so can contain things like your header, footer, and default page structure. It is also used as the “app shell” when loading your site from a service worker.

A small layout component might look something like this.

import React from "react" import { Link } from "gatsby" class Layout extends React . Component { render() { return ( <div> < Link to= "/" > Home </ Link > <br /> { } { this .props.children()} </div> ) } } export default Layout

Every page will be rendered as children of the Layout component:

<Layout> <Page /> </Layout>

Gatsbygram’s layout component is somewhat more complicated than most sites as it has logic to show clicked images in either a modal on larger screens or on their own page on smaller screens.

Read Gatsbygram’s Layout component on GitHub.

Client routing and pre-caching

Gatsby loads first a static server-rendered HTML page and then the JavaScript to convert the site into a web application. Which means that clicking around the site doesn’t require a page reload. Gatsby pre-caches code and data needed for other pages so that clicking on a link loads the next page instantly.

All the setup for this is handled behind the scenes. Gatsby uses @reach/router under the hood but generates all the configuration for you.

Normally page resources are pre-cached with a service worker. But as several browsers (Safari/Microsoft Edge) still don’t support Service Workers, the Gatsby <Link> component pre-caches resources for pages it links to by loading them into memory.

Plugins

Gatsby has always had a rich set of lifecycle APIs to allow you to hook into various events during development, building, and in the client.

Gatsby 1.0 adds new APIs and also adds a new plugin architecture. So functionality can now be extracted from sites and made reusable. Most of the new functionality in Gatsby 1.0 is powered by plugins.

Plugins are added to a site in its gatsby-config.js . Here’s what Gatsbygram’s config file looks like:

module .exports = { siteMetadata: { title: `Gatsbygram` }, plugins: [ { resolve: `gatsby-source-filesystem`, options: { name: `data`, path: `${__dirname}/data` } }, `gatsby-plugin-sharp`, `gatsby-transformer-sharp`, `gatsby-transformer-json`, `gatsby-plugin-glamor`, { resolve: `gatsby-plugin-manifest`, options: { name: `Gatsbygram`, short_name: `Gatsbygram`, start_url: `/`, background_color: `#f7f7f7`, theme_color: `# 191919 `, display: `minimal-ui` } }, `gatsby-plugin-offline`, { resolve: `gatsby-plugin-google-analytics`, options: { trackingId: `UA -91652198 -1 ` } } ] }

Styles

Gatsbygram uses two popular and complementary CSS-in-JS libraries, Typography.js and Glamor.

Typography.js is a powerful toolkit for building websites with beautiful design.

Gatsbygram uses Typography.js to generate the global styles for the site helping set the overall feel of the design.

Glamor lets you write real CSS in JavaScript inline in your React.js components. It is used for component styles.

Typography.js exposes two helper JavaScript functions, rhythm and scale to help keep your design in sync as you make changes. Instead of using hard-coded spacing values (which break as soon as you change your global theme), you use the Typography.js helper functions e.g.

import React from "react" ; import { rhythm, scale } from "../utils/typography" ; class SampleComponent extends React { render () { return ( <div { } css={{ padding: rhythm( 1 ), }} > <h1 css={{ ...scale( 6 / 5 ), }} > My sweet title </h1> <p> Hello friends</p> </div> ) } }

Together they allow you to quickly iterate on designs.

They also contribute to Gatsbygram’s excellent loading speed. The holy grail of CSS performance is inlined critical CSS. Meaning a) only ship a page with the CSS necessary to render that page and b) inline it in the <head> instead of putting it in a separate file. There are various tools to make this happen but they tend to involve extensive configuration and heavy post-processing.

But with Typography.js and Glamor you get optimized CSS with no tedious, error-prone bookkeeping. Typography.js (by definition) generates only global styles so its styles are included on every page. Glamor includes some clever server-rendering optimizations which I’ve implemented in the Gatsby Glamor plugin where it automatically extracts out the CSS used in components on the page being server rendered and automatically inlines those styles in the generated HTML page.

Super fast CSS by default. ???

Creating your own Gatsbygram

It’s easy to create your own “Gatsbygram” site from an Instagram account.

Instructions on setting up your own Gatsbygram site

git clone -b 1.0 git@github.com:gatsbyjs/gatsby.git cd gatsby/examples/gatsbygram npm install rm -r data node scrape .js INSTAGRAM_USERNAME npm run develop

While writing this post I scraped a few accounts and published their resulting “Gatsbygram” sites:

With thanks to Sam Bhagwat, Sunil Pai, Nolan Lawson, Nik Graf, Jeff Posnick, and Addy Osmani for their reviews.

And a special thanks to Kristo Jorgenson for his refactor of the “App structure” section.