© 2026 Hedgehog Software, LLC

TwitterGitHubDiscord
More
CommunitiesDocsAboutTermsPrivacy
Search
Star
Setup for Free
Drizzle TeamDT
Drizzle Team•16mo ago•
3 replies
Anthony

Race condition executing a common pattern (select or insert)

I'm having trouble understanding how to execute a common pattern in Postgres and I'm using Drizzle as an ORM adapted. The common pattern is this: I want to fetch a single row by some query, for example

let record = await db.query.records.findFirst({
    where: eq(records.phoneNumber, '+15555555555'),
    orderBy: desc(records.createdAt)
});
let record = await db.query.records.findFirst({
    where: eq(records.phoneNumber, '+15555555555'),
    orderBy: desc(records.createdAt)
});


But if that record doesn't exist I want to create a new record and use that one later on in the file.

let record = await db.query.records.findFirst({
    where: eq(records.phoneNumber, '+15555555555'),
    orderBy: asc(records.createdAt)
});

if (!record) {
    const [newRecord] = await db.insert(records)
        .values({
            phoneNumber: '+15555555555'
        })
        .returning();
    
    record = newRecord;
}
let record = await db.query.records.findFirst({
    where: eq(records.phoneNumber, '+15555555555'),
    orderBy: asc(records.createdAt)
});

if (!record) {
    const [newRecord] = await db.insert(records)
        .values({
            phoneNumber: '+15555555555'
        })
        .returning();
    
    record = newRecord;
}


Now, the thing is I am doing this in an API route that might be called multiple times at the same time and I want to avoid race conditions so I wrapped this in a transaction.

const record = await db.transaction(async (tx) => {
    // First try to find the existing record
    const existingRecord = await tx.query.records.findFirst({
        where: eq(records.phoneNumber, '+15555555555'),
        orderBy: asc(records.createdAt)
    });

    if (existingRecord) {
        return existingRecord;
    }

    // If no record exists, create a new one
    const [newRecord] = await tx.insert(records)
        .values({
            phoneNumber: '+15555555555'
        })
        .returning();

    return newRecord;
});
const record = await db.transaction(async (tx) => {
    // First try to find the existing record
    const existingRecord = await tx.query.records.findFirst({
        where: eq(records.phoneNumber, '+15555555555'),
        orderBy: asc(records.createdAt)
    });

    if (existingRecord) {
        return existingRecord;
    }

    // If no record exists, create a new one
    const [newRecord] = await tx.insert(records)
        .values({
            phoneNumber: '+15555555555'
        })
        .returning();

    return newRecord;
});


Now the problem is that even though this is wrapped in a transaction, race conditions can still occur where 2 users call my API endpoint at the exact same time, and 2 new records are created. How do I update my API endpoint to avoid this scenario using Drizzle syntax or PostgreSQL?
Drizzle TeamJoin
The official Discord for all Drizzle related projects, such as Drizzle ORM, Drizzle Kit, Drizzle Studio and more!
11,879Members
Resources
Was this page helpful?

Similar Threads

Recent Announcements

Similar Threads

Db race condition
Drizzle TeamDTDrizzle Team / help
3y ago
insert from select
Drizzle TeamDTDrizzle Team / help
12mo ago
How to fix collision / race condition
Drizzle TeamDTDrizzle Team / help
15mo ago
Infer insert model for select in "Insert into ... select"
Drizzle TeamDTDrizzle Team / help
15mo ago