This is a full-stack development starter template that combines Next.js 15 with Cloudflare’s edge platform.
This template uses Cloudflare Workers for the serverless backend, Cloudflare D1 as the SQLite database, and Drizzle ORM for type-safe database queries.
It also includes a pre-built Todo API with full CRUD (Create, Read, Update, Delete) functionality.
The template is useful for developers looking to build scalable and performant applications without managing traditional server infrastructure.
Use Cases
- Building scalable web applications that require global edge distribution and fast response times.
- Creating API-first applications with TypeScript type safety and modern development practices.
- Developing serverless applications that need database functionality without managing infrastructure.
- Prototyping full-stack applications with rapid deployment and iteration capabilities.
- Building production-ready applications that benefit from Cloudflare’s global network and security features.
How to Use It
1. Clone the project repository and install the necessary dependencies.
git clone https://github.com/ifindev/fullstack-next-cloudflare.git
cd next-cf-app
pnpm install2. Set up your Cloudflare credentials. Create a .dev.vars file in the root of the project by copying the example file.
cp .dev.vars.example .dev.vars3. Populate this file with your Cloudflare Account ID and an API Token. You can find your Account ID on the main page of your Cloudflare dashboard. To create an API token, navigate to the API Tokens section and create a new token with permissions for D1 and Workers.
# Load .env.development* files when running `wrangler dev`
NEXTJS_ENV=development
# Drizzle Kit credentials for D1
# Get your Account ID from: https://dash.cloudflare.com/ (right sidebar)
# Get your API Token from: https://dash.cloudflare.com/profile/api-tokens
CLOUDFLARE_ACCOUNT_ID=your-account-id-here
CLOUDFLARE_D1_TOKEN=your-api-token-here
CLOUDFLARE_R2_URL=your-r2-url-here
CLOUDFLARE_API_TOKEN=your-api-token-here
# Authentication
BETTER_AUTH_SECRET=your-better-auth-secret # see https://www.better-auth.com/docs/installation
BETTER_AUTH_URL=http://localhost:3000 # Base URL of your app - should use the deployed URL in Workers for prod
# Google Auth : see https://www.better-auth.com/docs/authentication/google
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
3. The template is configured to work with a Cloudflare D1 database. The required database migrations are already included. To apply these migrations to your local development database, run the following command.
pnpm run db:migrate:local4. This command sets up the necessary tables in your local D1 instance. You can verify the setup by inspecting the database.
pnpm run db:inspect:local5. For an optimal development workflow, you should run two separate processes. The first process starts the Wrangler development server, which provides access to the local D1 database.
# In your first terminal
pnpm run wrangler:dev6. The second process starts the Next.js development server. This enables features like Hot Module Replacement for immediate feedback on code changes.
# In your second terminal
pnpm dev7. Your Next.js application will be available at http://localhost:3000, while the Cloudflare Workers runtime can be accessed at http://localhost:8787.
8. Before deploying your application to production, apply the database migrations to your production D1 database.
pnpm run db:migrate:prod9. After the migrations are complete, you can deploy the entire application with a single command.
pnpm run deployThis command builds the Next.js application, generates the worker script, and deploys it to your Cloudflare account.
Related Resources
- Better Auth: A framework-agnostic authentication library for TypeScript applications.
- Auth.js: An open-source authentication solution for web applications.
- Drizzle ORM Documentation – Official documentation for Drizzle ORM, including schema definition, query building, and TypeScript integration.
- Cloudflare R2: An object storage service that allows you to store large amounts of unstructured data without egress fees.
- Cloudflare Durable Objects: A storage solution that provides strongly consistent, transactional storage for serverless applications.
- Cloudflare KV: A global, low-latency key-value data store for your Cloudflare Workers applications.
FAQs
Q: What are the limitations of using D1 compared to traditional databases?
A: D1 is based on SQLite and has some limitations, including no support for stored procedures, limited concurrent write operations, and a maximum database size. However, it offers excellent read performance, global replication, and zero-configuration setup for most web applications.
Q: How does the development experience compare to traditional full-stack setups?
A: The development experience is similar to traditional setups but with added benefits of edge computing and global distribution. Local development uses actual D1 databases, and the deployment process is simpler than managing traditional server infrastructure.
Q: What should I do if I get a Property 'DB' does not exist on type 'CloudflareEnv' error?
A: This error occurs when the Cloudflare environment types are not generated. You can resolve this by running the command pnpm run cf-typegen in your project’s root directory.
Q: How can I view the data in my local D1 database?
A: You can use Drizzle Studio to get a graphical user interface for your database. Run pnpm run db:studio:local to open the studio for your local development database.
Q: Why does the Drizzle Studio command fail with accountId: undefined?
A: This issue usually means your .dev.vars file is missing or incorrectly configured. Confirm that the file exists and contains the correct CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_D1_TOKEN values.
Q: What is the difference between pnpm dev and pnpm run dev:cf?
A: The pnpm dev command starts only the Next.js development server with HMR, which requires running pnpm run wrangler:dev separately for database access. The pnpm run dev:cf command starts the application using the Cloudflare Workers runtime in a single command but does not support HMR.






