This is a minimal, hopefully beginner-friendly template you can use as a starting point for creating simple, database-backed React applications and hosting them on Cloudflare Pages.
Cloudflare Pages is a hosting service for websites and applications. Together with the Cloudflare D1 serverless database, you can host full-stack applications very cheaply, or for free.
- What's included?
- Why this, why now?
- Getting Started
- Deploying your project to Cloudflare Pages
- Working with the D1 SQLite database
- Working with API endpoints
- Working with Vite frontend
- License
This template contains the following components
- Frontend: ⚡️ React + Vite application with minimal libraries (see code:
/app
). - Backend: Cloudflare Pages Functions (see code:
/functions
) - Database: Cloudflare D1 SQLite database.
All of the code is written in TypeScript, but you can easily convert it to plain JavaScript instead.
Hosting serious, production-grade websites has never been easier: Companies like Vercel, Netlify and Render make it simple to host a static or a server-rendered website. Hosting databases is also easier than ever, using PlanetScale, Neon, Railway, or others.
For professional software engineers, these platforms make day-to-day work a breeze. However, for beginners and tinkerers, navigating the myriad of options, integrating different parts of the stack and understanding which parts of their offering are necessary for your use case can be confusing.
Cloudflare Pages and Cloudflare D1 are a great combination for hosting interactive, dynamic websites and applications for very cheaply, or in many cases, for free. You can write and deploy the frontend, backend and database to the cloud using just your favorite JavaScript framework and a serverless SQLite-compatible database. If you already know these tools, you can focus on programming your application instead of understanding different hosting solutions.
For local development, you'll need a recent version of Node.js.
To deploy the project to the internet, you'll be prompted to create a free Cloudflare account if you don't yet have one.
You can fork this template to your own account by pressing the Use this template button, and then clone the created repository.
If you are just trying things out, you can clone this repository directly, but before deploying to Cloudflare pages you should fork it to your own account so you can configure automatic deployments
Having cloned the repository locally, run:
npm install
Run the following command:
npx wrangler d1 create <your-database-name>
If you haven't yet logged into your Cloudflare account, you will be prompted to do so now. If you don't yet have an account, you can create one at this point.
Once the command completes, it will print a D1 database configuration into your terminal. Copy it and add it to your wrangler.toml
file in the project root directory:
[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "your-database-name"
database_id = "3762f371-4d12-410f-a6a1-50b6668d906e"
You should now be able to run the application locally with:
npm run dev
If you navigate to localhost:3000, you should see an empty website that displays the current time. The time is requested from a locally running Cloudflare D1 database, via a serverless edge function.
You can now start working on your application. To continue reading, follow either the deployment guide or start by defining a database schema locally.
Cloudflare Pages allows you to deploy automatically from a GitHub repository. Let's set that up:
- Make sure your project is uploaded to GitHub (or follow the Deploy from your local machine guide below instead).
- Go to pages.cloudflare.com and create a new account, or login to your existing Cloudflare account.
- Press Create application, and then:
- Switch to the Pages tab.
- Press Connect to git
- Select your repository
- Choose a project name and production branch (usually
main
) - Configure the following build settings:
- Build command:
npm run build
- Build output directory:
dist
- Build command:
- Press Save and Deploy
Cloudflare Pages will now automatically deploy your application after every commit to the production branch you chose above.
If you don't want to automatically deploy from git, you can deploy by running the following command below:
npm run deploy
Follow the instructions presented in your terminal. You will choose to either create a new Cloudflare Pages project or deploy to an existing project.
Whether or not you are using the automatic git deployment, you can always deploy from your local machine using the same npm run deploy
command.
Once the application is deployed, you'll need to configure your website to use the database.
First, make sure you have created a local database by following the Getting Started guide.
Then, let's make the database available to the site hosted on Cloudflare Pages:
- Deploy the project and newly configured database by following the Deploying your project to Cloudflare Pages instructions above.
- Log into your Cloudflare dashboard.
- Find your Pages project under Workers & Pages, and navigate to:
- Settings
- Functions
- D1 database bindings
- Press Get started, and add the following binding:
- Variable name: DB
- D1 database: your-database-name (use the name from your
wrangler.toml
- Redeploy the project:
npm run deploy
That should have done it! Your hosted application should now be able to access the D1 database.
If you followed the Getting Started and Deploying your project to Cloudflare Pages guides, you should now have a working web application that talks to an empty database.
TODO
The template contains one API endpoint: /api/time
, which queries the database for the current time, and returns it to the client as a JSON response:
export const onRequest = async (context) => {
// construct a query using the D1 bound to "context.env.DB"
const query = context.env.DB.prepare(`SELECT DATETIME('now') as time`);
// fetch and respond with data as JSON
const data = await query.first();
return Response.json(data);
};
The API endpoints are created by mirroring the desired URL as a file path under the /functions
directory.
For example, if we were creating an application for listing and creating products, you could create a file /api/products.ts
to respond with a list of products when a request is made to /api/products
. You can also use dynamic route parameters such as /api/products/[id].ts
, which could return a single product when calling /api/products/123
or /api/products/456
:
// functions/products/[id].ts
export const onRequest = async (context) => {
// read the value of [id] url fragment from "context.params"
const productId = context.params.id
// construct a query using the D1 bound to "context.env.DB"
const query = context.env.DB
.prepare(`SELECT * FROM products WHERE product_id = ?`)
.bind(productId);
// fetch and respond with data
const data = await query.first();
return Response.json(data);
};
If you have any question about Functions routing, read in the official Cloudflare documentation.
The frontend app is a standard blank Vite React Single Page Application (SPA). This means that the frontend is a "pure frontend": all the code runs in the user's browser, and not on a server.
If you have already learned plain JavaScript and React, you already know everything you need to get started.
However, unlike opinionated server-side frameworks like Next.js or Remix, a plain React application it up to you to decide how to load data from a server, and how to structure the navigation between pages in your application.
To make these tasks easier, this template includes two libraries: React Query and React Router.
These libraries are optional, and you can choose not to use them. But if you do, read on for more information.
TODO
See React Query documentation for more information.
TODO
See React Router documentation for more information.
TODO
TODO
MIT