Embrace the Jamstack: Building and Deploying Scalable Sites with Next.js and Cloudflare Workers

The web development world has evolved exponentially over the last few years, and the rise of Jamstack has proven to be a game-changer. With their ability to deliver feature-rich, highly scalable websites that load incredibly fast, Jamstack sites combine several technologies and practices to deliver optimal site performance.

In this tutorial, we'll explore how you can leverage the power of Jamstack architecture by building a website with Next.js and deploying it with Cloudflare Workers. We'll cover core concepts such as static pages, dynamic routing, and global API support in a serverless environment. So let's get started!

What is Jamstack?

Jamstack (JavaScript, APIs, and Markup) is a modern web development architecture that leverages pre-built markup, serverless functions, and CDNs to deliver high-quality web experiences. In simpler terms, Jamstack combines modern frontend frameworks with serverless APIs and a globally-distributed content delivery network (CDN).

With Jamstack, there is no need for a server or a database to be involved in serving web pages. Instead, you employ a combination of static assets, client-side JavaScript, and serverless functions (if necessary) to build your site.

Why use Jamstack design?

Jamstack websites offer several advantages over traditional server-rendered websites. Some of the most noteworthy benefits include:

  • Increased site speed and performance: By removing the need for server-side processing, Jamstack sites serve content faster.
  • Better scalability: The low cost of serving static assets and the ability to leverage serverless APIs makes scaling much easier.
  • Better security: Jamstack sites are inherently more secure because the serverless infrastructure doesn't have any open ports, which consequently reduces the risk of attacks.
  • Lower Costs: The reduced need for server infrastructure and the use of an edge network reduce the development and operation costs.

How to Build a Jamstack Site with Next.js and Cloudflare Workers

Now, let's explore how to create a Jamstack site with Next.js and then deploy it with Cloudflare Workers.

Step 1: Setting up Your Environment

We will assume that you already have Node.js installed on the machine where you are building your site. If not, navigate to the Node.js website to download the latest version for your OS and install.

Next, install Next.js globally on your machine by running the following command:

npm install -g next

If you're not familiar with Next.js, it is a React-based framework that simplifies server-side rendering (SSR) of React applications. By running JavaScript code on the server, the content appears faster for users because the server provides an already rendered HTML page directly in the browser.

Step 2: Creating a Next.js Project

Now that we have all necessary tools installed, we can create a new Next.js project. In your terminal, execute the following command:

npx create-next-app

This command creates a new Next.js project named "my-jamstack-app." CD into your new project directory by running:

cd my-jamstack-app

Step 3: Building a Static Site

Next.js is designed to help you build statically generated websites, meaning that all of your pages are pre-built and served as HTML files. This type of site architecture has several advantages that align perfectly with Jamstack's principles.

To get started, let's modify the default Next.js homepage to include a few elements. Open the pages/index.js file and replace the contents of the file with the following:


import Head from 'next/head';

export default function Home() {
  return (
    <>
      <Head>
        <title>Welcome to my Jamstack App</title>
      </Head>
      <h1>Hello, World!</h1>
      <p>This demo is built with Jamstack principles and Next.js</p>
    </>
  )
}

Save the file, and then initiate the development server by running:

npm run dev

Now open your browser to http://localhost:3000, and you should see the new homepage where we greet our users with the message "Hello, World!"

At this point, you have created a basic statically generated site with Next.js. However, to move forward with a Jamstack site, we need to add a global API that we can query to get data and some routing for our site.

Step 4: Adding Global APIs and Dynamic Routing

Firebase is an easy-to-use NoSQL database that also supports REST APIs. This feature makes Firebase a perfect fit to include an API in our Jamstack website. Let's create a new Firebase database from the Firebase console, and add some random data to it.

Next, install the official Firebase JavaScript library in your project from the terminal by running the following command:

npm install firebase

Let's create a new file called `posts.js` inside a new folder called `api` as shown below. This file will act as our API:


import firebase from "firebase";

//initialize Firebase SDK
const firebaseConfig = {
  //the firebase config object you can get from your firebase console dashboard
};

try {
  firebase.initializeApp(firebaseConfig);
} catch (err) {
  if (!/already exists/.test(err.message)) {
    console.error('Firebase initialization error', err.stack);
  }
}

const db = firebase.database().ref();

const getAllPosts = () => {
  const query = db.child("posts");
  return query.once("value").then((snapshot) => {
    let posts = [];
    snapshot.forEach((childSnapshot) => {
      posts = [...posts, childSnapshot.val()];
    });

    return posts;
  });
};

export default async function handler(req, res) {
  const posts = await getAllPosts();
  res.status(200).json(posts);
}

The `getAllPosts` function queries Firebase API to get all posts and return them as an array. Our API returns a JSON response that we can use in any part of our React/Jamstack app.

Next, let's add a new route (`/posts`) to our app that fetches our API and lists all posts:


import Head from 'next/head';
import Link from 'next/link';

export async function getStaticProps() {
  const res = await fetch(`${process.env.NEXT_PUBLIC_API_ENDPOINT}/posts`);
  const posts = await res.json();

  return {
    props: { posts },
    revalidate: 60,
  };
}

export default function Posts({ posts }) {
  return (
    <>
      <Head>
        <title>Posts | My Jamstack App</title>
      </Head>
      <h1>All posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            <Link href={`/posts/${post.id}`} passHref>
              <a>{post.title}</a>
            </Link>
          </li>
        ))}
      </ul>
    </>
  );
}

The `getStaticProps` function will generate the page content during the build-time and return the data(`posts`) as a fallback. The navigate our visitors through the post pages, we insert links to each post, making it our first dynamic routing.

Step 5: Working with Cloudflare Workers

Using Cloudflare Workers is an excellent means of deploying our Jamstack site. It provides scalability and security to our site. This service is part of Cloudflare's CDN, so all Workers functions get deployed globally meaning our website gets faster response times and decreased latency.

Start by creating a Cloudflare account if you haven't already done so, or log into your account. Next, create a new worker, and you will be redirected to the Cloudflare dashboard.

Go to the Setting tab inside the created worker and overwrite the default code with the following:


addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const initialResults = await fetch(`${process.env.NEXT_PUBLIC_API_ENDPOINT}/posts`);
  let posts = await initialResults.json();

  const formattedResults = posts
    .map(({ id, title }) => ({
      id,
      title,
      url: 'https://{insert your website domain}/posts/' + id,
    }));

  return new Response(JSON.stringify(formattedResults), {
    headers: {
      "content-type": "application/json;charset=UTF-8",
      "access-control-allow-origin": "*"
    },
  });
}

This code creates a new Cloudflare Worker that will act as our new API that queries our `posts` API function and then maps its response to an array of objects for easy integration into our Jamstack site. Make sure to replace the `{insert your website domain}` with your actual site's domain name. Also, make a note of the Worker URL displayed on the Cloudflare console as we will need it for the next step.

Step 6: Updating Your Next.js Site URL

Now that we have a deployed Worker, we need to update the endpoint in our Next.js project. Open the next.config.js file and add the following code:


module.exports = {
  env: {
    NEXT_PUBLIC_API_ENDPOINT: {insert cloudflare worker URL here}
  }
};

Make sure to replace the "insert cloudflare worker URL here" with the actual URL of your Cloudflare worker endpoint.

Step 7: Build and Deploy with Vercel

The final step is to deploy our website with Vercel, which is the go-to platform for Next.js projects. If you haven't already signed up for a free account, go ahead and do so, then follow these instructions:

  • Create and verify a new Vercel account
  • Link your Next.js GitHub repository with Vercel
  • Set your environment variables in the Vercel app
  • Configure the build and deploy settings according to your needs on Vercel
  • Initiate the build by syncing your latest code updates to your repository

Once your site has been deployed successfully, check your deployed domain to see our Jamstack site in action. You should have a working website with all of its features, scalability, and security features enabled.

Conclusion

And there you have it – a comprehensive tutorial on building Jamstack sites with Next.js and deploying them with Cloudflare Workers. By making full use of available services for web development, we can produce high-quality, scalable websites that work beautifully across all platforms nearly immediately. Adopting these practices can save valuable development time while increasing site performance. With web development evolving continuously, it is essential to stay on top of recommended practices and technologies – Jamstack, Next.js, and Cloudflare all point to a promising future for web development and optimization.