DEV Community

Cover image for Submitting a Next.js Form to Google Sheets
Masaud Ahmod
Masaud Ahmod

Posted on

Submitting a Next.js Form to Google Sheets

Collecting user feedback or leads on a landing page is a must-have feature for modern applications. While setting up a full backend can be heavy for a simple landing page, you can use Google Sheets as a free and reliable database.

In this guide, we’ll build a Contact Form in Next.js (with TypeScript) that stores form submissions directly into a Google Sheet using Google Apps Script.

This method is:
✅ Free
✅ Serverless (no backend required)
✅ Scalable for MVPs & landing pages


🚀 Step 1: Set Up Google Sheet & Apps Script

  1. Create a Google Sheet
  • Go to Google Sheets and create a new sheet.

  • Add headers in the first row: Name, Email, Message, Timestamp.

  1. Open Script Editor
  • In Google Sheets, click: ExtensionsApp Script
  1. Paste Script
function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = JSON.parse(e.postData.contents);

  sheet.appendRow([
    data.name,
    data.email,
    data.message,
    new Date()
  ]);

  return ContentService
    .createTextOutput(JSON.stringify({ status: "success" }))
    .setMimeType(ContentService.MimeType.JSON);
}

Enter fullscreen mode Exit fullscreen mode
  1. Deploy as Web App

⚛️ Step 2: Create Next.js Contact Form Component

Here’s the React component with loading state:

"use client";
import { useState } from "react";

export default function ContactForm() {
  const [form, setForm] = useState({ name: "", email: "", message: "" });
  const [loading, setLoading] = useState(false);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    setForm({ ...form, [e.target.name]: e.target.value });
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);

    try {
      const res = await fetch("YOUR_GOOGLE_SCRIPT_URL", {
        method: "POST",
        body: JSON.stringify(form),
      });

      const result = await res.json();
      if (result.status === "success") {
        alert("✅ Form submitted successfully!");
        setForm({ name: "", email: "", message: "" });
      } else {
        alert("❌ Something went wrong!");
      }
    } catch (error) {
      console.error(error);
      alert("⚠️ Error submitting form!");
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4 max-w-md mx-auto">
      <input
        type="text"
        name="name"
        placeholder="Your Name"
        value={form.name}
        onChange={handleChange}
        className="w-full border p-2 rounded"
        required
      />
      <input
        type="email"
        name="email"
        placeholder="Your Email"
        value={form.email}
        onChange={handleChange}
        className="w-full border p-2 rounded"
        required
      />
      <textarea
        name="message"
        placeholder="Your Message"
        value={form.message}
        onChange={handleChange}
        className="w-full border p-2 rounded"
      />
      <button
        type="submit"
        disabled={loading}
        className={`px-4 py-2 rounded text-white ${
          loading ? "bg-gray-400 cursor-not-allowed" : "bg-blue-600"
        }`}
      >
        {loading ? "Submitting..." : "Submit"}
      </button>
    </form>
  );
}

Enter fullscreen mode Exit fullscreen mode

📊 Step 3: Test the Integration

  • Deploy your Next.js project (npm run dev or vercel deploy).

  • Submit the form.

  • Check your Google Sheet → new row should appear with the form data. 🎉


🌟 Why Use This Approach?

  • Fast Setup: No backend required.

  • Cost-effective: 100% free with Google.

  • Easy migration: Later you can replace Google Sheets with a real backend (Node.js, Express, MongoDB).

Top comments (0)