Next.js 14 with Google Sheets (The Easy Way)
NextJS

Next.js 14 with Google Sheets (The Easy Way)

Easily integrate Google Sheets with Next.js 14 using Google Apps Script. Follow our step-by-step guide to set up a dynamic and interactive application.

5 min read

Sometimes, you just need to save some data into Google Sheets quickly and efficiently without going through the hassle of setting up Google’s Sheets API and SDK. If you’re looking for a fast and straightforward way to handle data storage in your Next.js 14 application, then this tutorial is for you!

In this guide, we’ll explore how to integrate Google Sheets with a Next.js 14 application. This powerful combination allows you to use Google Sheets as a simple backend for storing and retrieving data, making your Next.js application more dynamic and interactive.

Setting Up Google Sheets and Apps Script

Step 1: Create a Google Sheet

  1. Open Google Sheets and create a new spreadsheet.
  2. Rename the first sheet to TODO for easy reference.
  3. Add headings: Task and IS_DONE.

Step 2: Create an Apps Script

  1. Click on Extensions in the menu and select Apps Script.
  2. Replace the default code with the following script.
 const sheets = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/<UniqueId>/edit?gid=0#gid=0");
 
 
 //if you have changed your sheet name then replace the below Sheet1 with your sheet name
const sheet = sheets.getSheetByName("Sheet1");
 
 
function doGet(e) {
  var data = sheet.getDataRange().getValues();
  
  return ContentService
    .createTextOutput(JSON.stringify({
      status: true,
      message: "Fetched Successfully.",
      data
    }));
}
 
function doPost(e) {
  const { task, is_done } = e.parameter;
 
  sheet.appendRow([task, is_done]);
 
  return ContentService
    .createTextOutput(JSON.stringify({
      status: true,
      message: "Saved Successfully.",
      data: e.parameter
    }));
}
  1. Replace <UniqueId> with your sheet’s unique ID.
  2. Save the script and deploy it as a web app.
  3. Click on Deploy > New Deployment.
  4. Select Web app and set the permissions to Anyone.
  5. Copy the Web app URL for use in your Next.js project.

Setting Up the Next.js 14 Application

Step 1: Create a New Next.js Project

  • Open your terminal and create a new Next.js project:
npx create-next-app@14 google-sheets-nextjs
cd google-sheets-nextjs

Step 2: Create API Functions

  1. Create a file lib/api.ts and add the following code to handle API requests:
lib/api.ts
const API_URL = 'https://script.google.com/macros/s/<id>/exec';
 
 
export interface ITodo {
  task: string,
  is_done: boolean
}
 
export const fetchData = async (): Promise<ITodo[]> => {
  try {
    const response = await fetch(API_URL);
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    return data.data as ITodo[];
  } catch (error) {
    console.error('Error fetching data:', error);
    return [];
  }
};
 
export const addData = async (payload: FormData): Promise<ITodo[]> => {
  try {
    const response = await fetch(API_URL, {
      method: "POST",
      body: payload
    });
 
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    return data.data as ITodo[];
 
  } catch (error) {
    console.error('Error adding data:', error);
    return [];
  }
};
  1. Replace <id> with your Web app ID from Apps Script.

Building the Frontend

Step 1: Create a Data Display Component

  1. Create a file components/Todo.tsx .
components/Todo.tsx
import React from "react";
 
const Todo = ({ todos }: { todos: any[] }) => {
 
  return (
    <div>
      {todos.length === 0 ? (
        <p className="text-gray-500">No tasks found.</p>
      ) : (
        <ul className="space-y-2">
          {todos.slice(1).map(([task, is_done], index) => (
            <li key={index} className="p-2 border border-gray-300 rounded">
              <span className={`task ${is_done ? "line-through" : ""}`}>
                {task}
              </span>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};
 
export default Todo;

Step 2: Fetch Data and Display in Home Page

  1. Update the app/page.tsx.
app/page.tsx
"use client";
 
import { useEffect, useState } from "react";
import { addData, fetchData, ITodo } from "./api";
import Todo from "./components/Todo";
 
export default function Home() {
  const [todos, setTodos] = useState<any[]>([]);
  const [form, setForm] = useState<ITodo>({
    task: "",
    is_done: false
  });
  const [loading, setLoading] = useState(false);
 
  useEffect(() => {
    const getData = async () => {
      setLoading(true);
      try {
        const data = await fetchData();
        setTodos(data);
      } catch (error) {
        console.error("Error fetching data:", error);
      } finally {
        setLoading(false);
      }
    };
    getData();
  }, []);
 
  const handleSubmit = async (e: any) => {
    e.preventDefault();
 
    setLoading(true);
    try {
      const formData = new FormData();
      formData.append('task', form.task);
      formData.append('is_done', form.is_done ? 'true' : 'false');
 
      await addData(formData);
      const updatedData = await fetchData();
      setTodos(updatedData);
      setForm({ task: "", is_done: false });
    } catch (error) {
      console.error("Error adding data:", error);
    } finally {
      setLoading(false);
    }
  };
 
  return (
    <div className="mx-auto p-4 container">
      <h1 className="mb-4 font-bold text-2xl">Next.js 14 with Google Sheets</h1>
      <Todo todos={todos} />
 
      {loading && (
        <div className="fixed inset-0 flex justify-center items-center bg-gray-100 bg-opacity-50">
          <div className="bg-white shadow-md p-4 rounded">Loading...</div>
        </div>
      )}
 
      <form onSubmit={handleSubmit} className="mt-4">
        <div className="flex flex-col space-y-2">
          <input
            type="text"
            value={form.task}
            onChange={(e) => setForm({ ...form, task: e.target.value })}
            placeholder="Task"
            className="p-2 border border-gray-300 rounded w-full"
          />
          <label className="flex items-center space-x-2">
            <input
              type="checkbox"
              checked={form.is_done}
              onChange={(e) => setForm({ ...form, is_done: e.target.checked })}
              className="form-checkbox"
            />
            <span className="text-sm">Completed</span>
          </label>
          <button
            type="submit"
            className="bg-blue-500 p-2 rounded text-white"
            disabled={loading}
          >
            Add Task
          </button>
        </div>
      </form>
    </div>
  );
}
  1. Update gloabl.css.
@tailwind base;
@tailwind components;
@tailwind utilities;

Now run npm run dev

and open http://localhost:3000/

It should look like something this.

nextjs 14 with google sheet.webp

It will add data realtime like below.

nextjs 14 with google sheet 1.webp

Your app should look like this

nextjs 14 with google sheet 2.webp

Conclusion

By following these steps, you’ve successfully integrated Google Sheets with a Next.js 14 application using Google Apps Script.