{
  "id": 15665653,
  "title": "The double-booking bug I shipped in my Next.js booking app (and how Postgres fixed it)",
  "url": "https://urgent.news/2026/10/19/the-double-booking-bug-i-shipped-in-my-next-js-booking-app-and-how",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-19T22:42:33.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/slotkdev/the-double-booking-bug-i-shipped-in-my-nextjs-booking-app-and-how-postgres-fixed-it-f7j"
  },
  "original_language": "en",
  "account": "During an audit of my Next.js booking app, I discovered that the double booking protection mechanism was flawed. The bug allowed two requests for the same time slot to proceed, resulting in concurrent INSERT operations. To address this, I implemented a fix using Postgres advisory locks within a transaction-scoped scope. By locking on the resource ID, the system serializes bookings for each resource, preventing conflicts while allowing parallel bookings for different resources. The use of advisory locks was chosen over a unique constraint or exclusion constraint because it offers simplicity and readability without the need for additional extensions. For serverless deployments like Supabase, configuring the database with prepare: false enables the transaction-scoped lock to operate effectively. Additionally, I resolved a timezone bug by converting the business's wall-clock time to UTC using the tenant's IANA timezone, ensuring accurate slot availability across different time zones. This solution, part of the SlotKit template, was implemented to enhance the reliability and accuracy of the booking system.",
  "summary": "I build a multi-tenant booking template with Next.js, Drizzle and Postgres. During an audit I found that my \"double booking protection\" didn't protect anything. Here's the bug, and the fix. The naive version This is roughly what I had: const conflict = await db . select (). from ( bookings ). where ( and ( eq ( bookings . resourceId , resourceId ), gte ( bookings . startTime , start ), lte (…",
  "key_points": [
    "Double-booking bug flaw in Next.js booking app's protection mechanism",
    "Postgres advisory locks implemented to serialize bookings per resource",
    "Timezone bug resolved by converting to UTC using tenant's IANA timezone"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}