Gatsby and NextJS do similar things differently. One is better for websites, the other for webapps. In episode 17 of CodeWithSwiz we explore the biggest difference.
CodeWithSwiz is a twice-a-week live show. Like a podcast with video and fun hacking. Focused on experiments. Join live Wednesdays and Sundays
Spring last year I had a flash of insight: Modern web apps are static first! It solves so many problems 🤯
Like time to first byte performance, loading spinners of death on bad wifi, and you can host from CDNs backed by a serverless data source. Works great.
Following that hunch I built Spark Joy on a series of streams. The app you see under every email and article.
Click a link, go to a page, answer followup questions. Works great.
Except when the email software says 15 readers clicked a vote and Spark Joy gets 5 votes 🤔
ServerSideRendering and ServerSideGeneration
When do you save that vote to the database?
With server side rendering your pages are created in advance. You deploy your site, go through the database, render a page for each relevant entry and turn it into HTML with data baked-in.
When users load a page, it hydrates and becomes a React app. You make requests in the browser and save the vote.
This is the approach Gatsby uses.
Server side rendering
You create pages like this in gatsby-node.js
:
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(`
query {
widgetsapi {
allWidget {
userId
widgetId
widgetType
followupQuestions
}
}
}
`)
result.data.widgetsapi.allWidget.forEach(
({ userId, widgetId, widgetType, followupQuestions }) => {
const votePath = path.resolve("./src/pages/vote.js")
createPage({
path: `/${widgetId}/thumbsup`,
component: votePath,
context: {
userId,
widgetId,
followupQuestions,
widgetType,
voteType: "thumbsup",
},
})
}
)
}
The pattern you'll see is:
- Fetch data with GraphQL
- Iterate over data
createPage
for each with a data-driven URL
Your page becomes static HTML served from a CDN. No servers. You read page params using the pageContext
prop.
const VotePage = ({ pageContext }) => {
const {
userId,
widgetId,
voteType,
followupQuestions,
widgetType,
} = pageContext
return (
<FullScreen>
<SEO title="Thank You" />
<FormView
voteType={voteType}
onSubmit={onSubmit}
followupQuestions={followupQuestions}
widgetType={widgetType}
/>
</FullScreen>
)
}
Use props baked-in during deploy, render the page. No loading spinners.
Because this is a static page, you save votes on load. And that's how you lose them. Folks load the page and bail before the save request completes.
More on that next time ✌️
Server side generation
NextJS supports server side rendering and it's gonna have the same problem: What if users bail before data saves?
A "revolutionary" new approach that NextJS offers is server side generation. You'll recognize this as "How websites used to work 10 years ago".
With server side generation you generate the page on-demand. User makes a request, serverless lambda (not managed by you) wakes up, fetches data, builds the page. User gets static HTML, it hydrates into a React app.
getServerSideProps
is how you turn that on:
export async function getServerSideProps({ params }) {
const { widgetId } = params
const { data } = await client.query({
query: gql`
query {
allWidget {
userId
widgetId
widgetType
followupQuestions
}
}
`,
})
// TODO: support a query to fetch this directly
const widget = data.allWidget.find((w) => w.widgetId === widgetId) || {}
return { props: { widget } }
}
Fetch data using GraphQL, return an object with props
. Supports redirects and other fun stuff.
Where it differs from websites of old, is that your app uses the same code to render on the server and in the browser. Seamlessly.
const VotePage = ({ widget }) => {
const { userId, widgetId, voteType, followupQuestions, widgetType } = widget
return (
<Container sx={{ textAlign: "center" }}>
<Head>
<title>Thank you</title>
</Head>
<FormView
voteType={voteType}
onSubmit={onSubmit}
followupQuestions={followupQuestions}
widgetType={widgetType}
/>
</Container>
)
}
You get data from props and use it to render the page. No loading spinners.
And unlike with Gatsby, you have a chance to save data on every page load before the page loads. Force users to wait. We'll try that next time.
The SSR vs SSG tradeoff
SSR and SSG do the same thing: Serve a page with data baked-in.
The difference is when that happens. When you deploy your site (Gatsby), when the first user hits a page (NextJS), or when every user hits the page (NextJS)?
Each approach gives you different performance characteristics.
- Gatsby build-time rendering creates slow deploys and fantastic time to first byte for every user
- NextJS on-demand static pages create fast deploys, fantastic first load for most users, and terrible performance when cache is cold
- NextJS server side generation creates fast deploys, slow page loads, and a chance to do things pre-load
Which is best depends on what you're doing.
Cheers,
~Swizec
PS: Gatsby looks like it's moving towards SSG, they now support filename-based dynamic routing
Continue reading about Gatsby to NextJS pt1, server-side-render or server-side-generate?
Semantically similar articles hand-picked by GPT-4
- SSR, SSRwR, SSG, CSR, WTFBBQ???
- Using YouTube as a data source in Gatsbyjs
- Your first NextJS app – CodeWithSwiz
- Exploring NextJS with a headless CMS, pt4 – CodeWithSwiz
- Why serverless fits side-projects perfectly
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️