Next JS Query Cloudflare D1 Database

I recently tried Cloudflare D1, and I was impressed by how fast it felt and how straightforward it was to use. I’d like to share how I connected it to my Next.js application. Hopefully, this tutorial will give you a basic understanding of how to get started.

For this example, I’ll use a simple login page to demonstrate how the application interacts with the database. This example focuses on database integration and does not include session management or password hashing, so it is intended for learning purposes. A production login system should include both.

Once you have set up Cloudflare D1 and created your database, the next step is to create a table. In this example, I created a table called user to store the user records.

How to do simple search query in D1 Database?

If you are using Next.js, start by adding the necessary imports to your action.ts file:

action.ts
import { getCloudflareContext } from “@opennextjs/cloudflare”;

after all your validation, please insert the code into the try{} block.

  const { env } = await getCloudflareContext({ async: true });
    // Matches the existing plain-text users table. Never log or return passwords.
    const user = await env.hometuition_db
      .prepare(“SELECT email FROM users WHERE email = ? AND password = ? LIMIT 1”)
      .bind(email, password)
      .first<{ email: string }>();
If you have notice, the D1 uses a simple format to query the database. The database needs to
  • prepare
  • bind

Once the query has arrived it will be save in the User constant

Note:
This guide assumes your Next.js project already has a Cloudflare D1 binding configured. Please do not copy blindly the code, there are alot of missing pieces.

Penang Web Consultant

Nova Web Business provides serverless database solutions for your applications. Need help getting started? Contact Justin for guidance and support.

 

Sample code for Cloudflare D1 Query

“use server”;
import { getCloudflareContext } from “@opennextjs/cloudflare”;
import { redirect } from “next/navigation”;
import { z } from “zod”;
const loginSchema = z.object({
  email: z.string({ error: “Email address is required.” })
    .trim()
    .min(1, “Email address is required.”)
    .email(“Enter a valid email address.”),
  password: z.string({ error: “Password is required.” })
    .min(1, “Password is required.”),
});
export async function loginAction(formData: FormData) {
  const result = loginSchema.safeParse({
    email: formData.get(“email”),
    password: formData.get(“password”),
  });
  if (!result.success) {
    return {
      success: false,
      errors: z.flattenError(result.error).fieldErrors,
    };
  }
  const { email, password } = result.data;
  try {
    const { env } = await getCloudflareContext({ async: true });
    // Matches the existing plain-text users table. Never log or return passwords.
    const user = await env.hometuition_db
      .prepare(“SELECT email FROM users WHERE email = ? AND password = ? LIMIT 1”)
      .bind(email, password)
      .first<{ email: string }>();
    if (!user) {
      return {
        success: false,
        message: “Incorrect email or password.”,
      };
    }
  } catch {
    return {
      success: false,
      message: “Unable to check your account right now. Please try again later.”,
    };
  }
  redirect(“/dashboard”);
}