We're live-coding on Twitch! Join us!
Easily Deploy a Fullstack Next.js App with Vercel

Easily Deploy a Fullstack Next.js App with Vercel

Developing and shipping production-ready applications to the web today couldn't be easier than with Next.js and Vercel. It provides a world-class developer experience right out of the box and is optimized for powering high-performance production workloads. Read on to get an overview of what makes Next.js so compelling to work with and how easy it is to get your work deployed to production.

Installation and Setup

Make sure you have npm installed on your system:

node -v && npm -v

You should see the respective version numbers printed to the console. If not, you can go to the official Node.js site to get installation instructions for your platform.

With the node toolchain installed on our machines, we can invoke the following to scaffold out a new Next.js project:

npx create-next-app my-amazing-app

Enter the directory you just created and start the development server:

cd my-amazing-app && npm run dev

Your app will be served on localhost:3000 by default and you'll be greeted with the default welcome screen when navigating to it with your browser.

Static Data Fetching

You can supply dynamic data to your pages at build-time via the getStaticProps data-fetching hook. This is great for marketing pages where data doesn't change too often and speed is the priority. Remove the default contents of pages/index.js and replace it with the following:

import Head from "next/head";

export default function Home({
  title = "Hello World!",
  metaContent = "Generic SEO pitch",
  copy = "I'm having writer's block.",
}) {
  return (
    <>
      <Head>
        <title>{title}</title>
        <meta content={metaContent} />
      </Head>
      <div>
        <h1>{title}</h1>
        <p>{copy}</p>
      </div>
    </>
  );
}

export const getStaticProps = async () => {
  // This is a full server-side Node environment,
  // which means that you can make network requests,
  // talk to databases, read from the file-system,
  // and do whatever you want to fetch your data.

  return {
    props: {
      title: "My Amazing Startup",
      metaContent: "Amazing SEO poetry",
      copy:
        "I'm in the business of making people smile. That's all I'm here for.",
    },
  };
};

Everything is the same as any typical React app, however, there are a few differences. First, you'll notice that we're not explicitly importing React because Next.js already brings it in scope. Next, you can see that we're able to set our page metadata from the <Head /> component and don't need to bring in another third-party library like react-helmet. Lastly, we've exported a function called getStaticProps which returns a props object with the title, metaContent, and copy keys. That allows us to destructure those props from our top-level page component and read in those values. Note that we've provided default values in case the props weren't supplied for good practice. When your Next.js project is built, these props are baked right into your pages with no runtime-overhead, which ultimately leads to better performance and reliability.

Incremental Static Regeneration

Next.js blurs the line between static and dynamic. Just because your data is fetched statically, doesn't mean that you're stuck with that same data until you re-deploy. Incremental Static Regeneration allows you to update existing pages by re-rendering them in the background as traffic comes in. All you need to do is add the revalidate key to the object you return from the getStaticProps function with the number of seconds you want to wait before revalidating and regenerating the page if data has changed. In our very contrived local example, you might not notice a difference, but it will truly come to life when you start querying data from a database or CMS.

export const getStaticProps = async () => {
  return {
    props: {
      title: "My Amazing Startup",
      copy:
        "I'm in the business of making people smile. That's all I'm here for.",
    },
    revalidate: 1, // number of seconds to wait before revalidating
  };
};

Server Side Rendering

Sometimes you have highly dynamic content that needs to change according to a number of variables. Maybe you want to inspect the request headers of incoming traffic and use that to determine how you want to render your page. For that, Next.js provides the getServerSideProps function and it isn't too different from the getStaticProps function that we've already seen.

Create a new file named hello-user-agent.js in your pages directory with the following contents:

import Head from "next/head";

export default function HelloUserAgent({ userAgent = "Nobody" }) {
  return (
    <>
      <Head>
        <title>Hello User Agent!</title>
      </Head>
      <p>
        {" "}
        Hi <em>{userAgent}</em> !{" "}
      </p>
    </>
  );
}

export const getServerSideProps = async ({ req }) => {
  return {
    props: {
      userAgent: req.headers["user-agent"],
    },
  };
};

This page follows a similar structure from our index.js home page, but has one tiny difference. Instead of exporting a getStaticProps function below our page component, we are exporting a function named getServerSideProps. Also notice that we are now destructuring a Node.js HTTP Incoming Message object and reading values from it in our function body. This page is completely rendered in a server environment powered by a lightweight Serverless Function and provides fresh props to your page every time the page is requested. If you navigate to localhost:3000/hello-user-agent, you'll see your browser's user agent string painted on the screen.

It should be mentioned that rendering a page in this fashion does come with a slight performance hit. If the function that is rendering your page hasn't been accessed for a couple of minutes, it can take a few moments (500 - 800 ms on average) to start up. This is commonly referred to as the cold start problem. A solid caching strategy can help mitigate this problem.

API Routes

API Routes allow you to create HTTP request handlers using the same file-system routing structure that we just saw on the frontend. When we created our project with create-next-app, an API route was already generated for us at pages/api/hello.js with the following contents:

export default (req, res) => {
  res.statusCode = 200
  res.json({ name: 'John Doe' })
}

If you navigate to localhost:3000/api/hello you'll get a JSON response returned from the function. API Routes are great for things like quickly connecting to a database and returning results or processing a form and sending emails.

Deploy to Vercel

Now that we've got a feel for how Next.js works, we need a way to get it up on the internet. Vercel is a deployment platform for frontend projects made by the same people that created Next.js, so its only natural that the deployment experience feels as simple as the development experience.

To get started, Initialize a new git repository and push it up to a Git provider. Once you have a URL for your repository, navigate to https://deploy.new/ and you will be taken through the import flow. If you don't already have an account, a new one will be created for you and a deployment will be made to your account. That's all there is to it! Your Next.js project is deployed all across the world through the Vercel Edge Network. Now every time you push changes or create a new branch, a new deployment will be made for you and your URL will be updated accordingly. You can learn more about the Vercel platform by consulting their documentation.

You can also use the Vercel CLI to make a deployment by running the vercel command from your project root, although the Git workflow is an ideal setup for iterating on a production app.

Conclusion

Next.js is a comprehensive framework for projects of any scale, but it hides a lot of details and has a strong focus on minimalism. It provides a hybrid rendering model to give you per-page control over whether you need static markup with pre-populated props supplied at build time or server-rendered pages with dynamic data requirements for every request. API routes help you get a backend up and running without reaching for Express or other API frameworks. We've covered the main features of Next.js, but have only scratched the surface. Head over to the official docs to go deeper and check out the interactive learning tutorial to build your own blog from scratch!