npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nuxt-pg

v0.0.19

Published

Seamless Nuxt 'pg' integration with event context-aware transaction handling.

Readme

nuxt-pg

PostgreSQL database module for Nuxt with automatic transaction management

npm version License

nuxt-pg provides a clean, type-safe PostgreSQL integration for Nuxt 3+ with automatic transaction context tracking. Write cleaner code by eliminating transaction parameter passing throughout your application.

✨ Features

  • 🔄 Automatic Transaction Context - No need to pass transaction objects through function calls
  • 🎯 Clean API - Simple getDatabase() composable for all database operations
  • 🔒 Type-Safe - Full TypeScript support with proper type inference
  • Connection Pooling - Built-in connection pool management with node-postgres
  • ⚙️ Flexible Pool Configuration - Customize pool settings globally or per-environment
  • 🛡️ Request Isolation - Transactions are automatically scoped per-request
  • 🔌 Graceful Shutdown - Properly closes connections on server shutdown
  • 🧪 Fully Tested - Comprehensive test coverage

📦 Installation

npm install nuxt-pg pg

🚀 Quick Start

1. Add to your nuxt.config.ts

export default defineNuxtConfig({
    modules: ['nuxt-pg'],
    
    runtimeConfig: {
        nuxtpg: {
            db: {
                connectionString: process.env.DATABASE_URL
            },
            dev: {
                db: {
                    connectionString: process.env.DEV_DATABASE_URL
                }
            }
        }
    },
    
    experimental: {
        asyncContext: true  // Required for automatic transaction tracking
    }
})

2. Use in your API routes

// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
    const db = getDatabase()
    const id = getRouterParam(event, 'id')
    
    const users = await db.query(
        'SELECT * FROM users WHERE id = $1',
        [id]
    )
    
    return users[0]
})

📖 Usage

Basic Queries

const db = getDatabase()

// Simple query
const users = await db.query('SELECT * FROM users')

// With parameters
const user = await db.query(
    'SELECT * FROM users WHERE email = $1',
    ['[email protected]']
)

// With TypeScript types
interface User {
    id: string
    name: string
    email: string
}

const users = await db.query<User>(
    'SELECT * FROM users WHERE active = $1',
    [true]
)

Transactions

Automatic (Recommended)

export default defineEventHandler(async (event) => {
    const db = getDatabase()
    
    return await db.transactional(async (txn) => {
        // All queries automatically use the same transaction
        await txn.query('INSERT INTO users (name) VALUES ($1)', ['Alice'])
        await txn.query('INSERT INTO profiles (user_id) VALUES ($1)', [userId])
        
        // Automatically commits on success, rolls back on error
        return { success: true }
    })
})

Manual Control

export default defineEventHandler(async (event) => {
    const db = getDatabase()
    
    await db.createTransaction()
    
    try {
        // All queries in this request context use the transaction
        await db.query('INSERT INTO users ...')
        await db.query('UPDATE profiles ...')
        
        await db.commitTransaction()
        return { success: true }
    } catch (error) {
        await db.rollbackTransaction()
        throw error
    }
})

Context-Aware Queries (No Transaction Passing!)

// repository.ts
export class UserRepository {
    static async create(data: CreateUserData) {
        const db = getDatabase()
        // Automatically uses transaction if one is active in the request context
        return db.query('INSERT INTO users ...', [...])
    }
    
    static async updateProfile(userId: string, data: any) {
        const db = getDatabase()
        // Also uses the same transaction automatically
        return db.query('UPDATE profiles ...', [...])
    }
}

// handler.ts
export default defineEventHandler(async (event) => {
    const db = getDatabase()
    
    // Both repository methods use the same transaction automatically!
    return await db.transactional(async () => {
        await UserRepository.create({ name: 'Alice' })
        await UserRepository.updateProfile(userId, { bio: 'Hello' })
    })
})

🔧 Configuration

Basic Configuration

runtimeConfig: {
    nuxtpg: {
        db: {
            connectionString: string  // Production connection string
        },
        dev: {
            db: {
                connectionString: string  // Development connection string
            }
        }
    }
}

Connection Pool Options

Customize the connection pool behavior using the pool configuration. Pool settings can be defined at three levels with the following priority (highest to lowest):

  1. Environment-specific (db.pool or dev.db.pool) - Highest priority
  2. Global (pool) - Applies to both dev and production
  3. Defaults - Built-in fallback values

Available Pool Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | maxConnections | number | 40 | Maximum number of clients in the pool | | minConnections | number | 2 | Minimum number of clients to maintain | | idleTimeoutMs | number | 30000 | Time (ms) a client can be idle before being closed | | connectionTimeoutMs | number | 2000 | Time (ms) to wait for a connection before timing out | | ssl | boolean | true | Enable SSL connection (uses rejectUnauthorized: false) |

Configuration Examples

Global Pool Settings (applies to both dev and production):

export default defineNuxtConfig({
    runtimeConfig: {
        nuxtpg: {
            pool: {
                maxConnections: 25,
                minConnections: 5,
                idleTimeoutMs: 60000,
                ssl: false
            },
            db: {
                connectionString: process.env.DATABASE_URL
            },
            dev: {
                db: {
                    connectionString: process.env.DEV_DATABASE_URL
                }
            }
        }
    }
})

Environment-Specific Pool Settings:

export default defineNuxtConfig({
    runtimeConfig: {
        nuxtpg: {
            // Production settings
            db: {
                connectionString: process.env.DATABASE_URL,
                pool: {
                    maxConnections: 50,
                    minConnections: 10,
                    ssl: true
                }
            },
            // Development settings
            dev: {
                db: {
                    connectionString: process.env.DEV_DATABASE_URL,
                    pool: {
                        maxConnections: 10,
                        minConnections: 2,
                        ssl: false
                    }
                }
            }
        }
    }
})

Mixed Configuration (global defaults with environment-specific overrides):

export default defineNuxtConfig({
    runtimeConfig: {
        nuxtpg: {
            // Global defaults
            pool: {
                minConnections: 3,
                idleTimeoutMs: 45000,
                connectionTimeoutMs: 3000
            },
            // Production overrides only what's needed
            db: {
                connectionString: process.env.DATABASE_URL,
                pool: {
                    maxConnections: 60,
                    ssl: true
                }
            },
            // Dev uses global settings but overrides maxConnections
            dev: {
                db: {
                    connectionString: process.env.DEV_DATABASE_URL,
                    pool: {
                        maxConnections: 8
                    }
                }
            }
        }
    }
})

📚 API Reference

getDatabase()

Returns the database service instance with the following methods:

query<T>(sql: string, params?: any[]): Promise<T[]>

Execute a SQL query. Automatically uses active transaction if available.

createTransaction(timeoutMs?: number): Promise<DBTransaction>

Start a new transaction in the current request context.

commitTransaction(): Promise<void>

Commit the active transaction.

rollbackTransaction(): Promise<void>

Rollback the active transaction.

transactional<T>(fn: (txn: DBTransaction) => Promise<T>, timeoutMs?: number): Promise<T>

Execute a function within a transaction with automatic commit/rollback.

isHealthy(): boolean

Check if the database connection pool is healthy.

shutdown(): Promise<void>

Gracefully shutdown the database service.

⚙️ How It Works

nuxt-pg leverages Nuxt's experimental asyncContext feature to track database transactions across async boundaries. When you start a transaction, it's stored in the request context and automatically used by all subsequent queries in that request - no need to pass transaction objects around!

// ❌ Old way (manual transaction passing)
await userService.create(data, transaction)
await profileService.create(profileData, transaction)

// ✅ New way (automatic context tracking)
await userService.create(data)
await profileService.create(profileData)

🧪 Testing

Tests are written using Vitest with full coverage of all components:

npm test

📝 Requirements

  • Nuxt 3.0+
  • Node.js 18+
  • PostgreSQL 12+
  • experimental.asyncContext: true must be enabled

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT License

Credits

Built with: