What’s in it
The template is a Next.js app written in TypeScript. It uses Drizzle to talk to Postgres and Vitest for tests.Scripts
The template pins Node 22 in
.tool-versions.
Local and production databases
The same code runs against two different databases:- Locally,
npm run devuses an embedded Postgres that runs inside Node and saves to alocal.dbfolder in your project. You don’t need to install Postgres. The folder is in.gitignore. - In production, the app connects to its own hosted Postgres database through
DATABASE_URL, which Fluid sets for you.
lib/db.ts picks the database for you, and both return the same Drizzle client. Your queries don’t change between the two. Data you create locally never reaches production.
Add a table
The template doesn’t run a migration step. Instead,ensureSchema() in lib/ensure-schema.ts runs CREATE TABLE IF NOT EXISTS statements the first time the app needs the database.
1
Define the table
Add the table to
lib/schema.ts with Drizzle’s pgTable.2
Create it on first use
Add a matching
CREATE TABLE IF NOT EXISTS statement to ensureSchema().3
Call ensureSchema first
Call
await ensureSchema() before your route’s first query.ensure-schema.ts.
The template creates two tables of its own: companies, with one row per installation of your droplet, and webhooks, an audit log of every webhook the app receives. Keep them.
Extend the app
Handle a webhook event
1
Write the handler
Add a file under
lib/handlers/, such as order-created.ts, that exports an async function.2
Register it
In
lib/handlers/index.ts, add registerHandler("order.created", handleOrderCreated).3
Turn on the webhook
In
lib/config/droplet.config.ts, set enabled: true on the matching webhook entry.Declare what your app registers
lib/config/droplet.config.ts lists everything your app registers with a company when the company installs it. Every entry ships with enabled: false. Turn one on only once the route behind it exists.
lib/config/droplet.config.ts
On install, the app registers each enabled entry for that company and saves the IDs. On uninstall, it removes them.