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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@omodaka/pinatinodb-adapter-neon

v0.1.0

Published

Neon/PostgreSQL adapter for PinatinoDB - serverless Postgres with IPFS sync

Downloads

6

Readme

@pinatinodb/neon-adapter

Automatically sync your Neon/PostgreSQL data to IPFS - perfect for serverless and edge functions.

🚀 Why Neon + PinatinoDB?

  • Serverless-First - Built for Vercel, Netlify, Cloudflare Workers
  • Edge-Compatible - Runs in edge runtimes (no Node.js required)
  • Zero Cold Starts - Neon's instant connections + IPFS backup
  • Automatic Sync - SQL queries auto-sync to IPFS
  • Type-Safe - Full TypeScript support
  • Cost-Effective - Pay only for what you use

📦 Installation

pnpm add @pinatinodb/neon-adapter @pinatinodb/core @neondatabase/serverless

🎯 Quick Start

import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';
import { PinatinoDB } from '@pinatinodb/core';

// 1. Initialize PinatinoDB
const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});
await pinatino.initialize();

// 2. Wrap Neon SQL with PinatinoDB
const sql = withPinatino(neon(process.env.DATABASE_URL!), {
  pinatino,
  strategy: 'write-through',
  logging: true
});

// 3. Use SQL normally - auto-syncs to IPFS!
const users = await sql`
  INSERT INTO users (name, email)
  VALUES ('Alice', '[email protected]')
  RETURNING *
`;
// ✅ Now in both Postgres AND IPFS!

🔧 Configuration

Basic Configuration

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino, // PinatinoDB instance (required)
  strategy: 'write-through', // Sync strategy (optional)
  tables: ['users', 'posts'], // Only sync these (optional)
  excludeTables: ['sessions'], // Skip these (optional)
  logging: true, // Enable logging (optional)
  primaryKey: 'id', // Primary key field (default: 'id')
  onError: (error, operation, table) => {
    // Custom error handler (optional)
    console.error(`Error in ${table}.${operation}:`, error);
  }
});

Selective Table Sync

// Only sync important tables
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  tables: ['users', 'posts', 'products']
});

// Or exclude temporary tables
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  excludeTables: ['sessions', 'logs', 'cache']
});

🔄 Sync Strategies

Write-Through (Default)

{
  strategy: 'write-through';
}
  • Writes to both Postgres and IPFS synchronously
  • Pros: Guaranteed consistency
  • Cons: Slower writes (~50ms IPFS overhead)
  • Use when: Data integrity is critical

Write-Behind

{
  strategy: 'write-behind';
}
  • Writes to Postgres immediately, queues IPFS async
  • Pros: Fast writes, no user-facing latency
  • Cons: Eventual consistency
  • Use when: Performance is critical (recommended for production)

None

{
  strategy: 'none';
}
  • No automatic sync
  • Use when: You want manual control or testing

📝 Usage Examples

Basic CRUD

// INSERT - Automatically synced to IPFS
const result = await sql`
  INSERT INTO users (name, email, age)
  VALUES ('Bob', '[email protected]', 35)
  RETURNING *
`;

// SELECT - Query from Postgres
const users = await sql`
  SELECT * FROM users
  WHERE age >= 18
  ORDER BY created_at DESC
  LIMIT 10
`;

// UPDATE - Synced to IPFS
await sql`
  UPDATE users
  SET age = 36
  WHERE email = '[email protected]'
  RETURNING *
`;

// DELETE - Removed from IPFS
await sql`
  DELETE FROM users
  WHERE id = ${userId}
`;

Transactions

import { neon, neonConfig } from '@neondatabase/serverless';

neonConfig.fetchConnectionCache = true;

const sql = withPinatino(neon(DATABASE_URL), { pinatino });

// Transactions work normally
await sql.transaction(async tx => {
  await tx`INSERT INTO users (name) VALUES ('Charlie')`;
  await tx`INSERT INTO posts (title, author_id) VALUES ('Hello', currval('users_id_seq'))`;
});
// Both inserts synced to IPFS after commit

Batch Operations

// Batch insert
const newUsers = [
  { name: 'Alice', email: '[email protected]' },
  { name: 'Bob', email: '[email protected]' },
  { name: 'Charlie', email: '[email protected]' }
];

for (const user of newUsers) {
  await sql`INSERT INTO users ${sql(user)} RETURNING *`;
}
// All synced to IPFS

🌐 Serverless Examples

Vercel Edge Function

// app/api/users/route.ts
import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';
import { PinatinoDB } from '@pinatinodb/core';

export const runtime = 'edge';

const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});
await pinatino.initialize();

const sql = withPinatino(neon(process.env.DATABASE_URL!), {
  pinatino,
  strategy: 'write-behind' // Fast for edge
});

export async function POST(request: Request) {
  const body = await request.json();

  const user = await sql`
    INSERT INTO users ${sql(body)}
    RETURNING *
  `;

  return Response.json(user);
}

Cloudflare Workers

import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';

export default {
  async fetch(request: Request, env: Env) {
    const pinatino = new PinatinoDB({
      pinata: { apiKey: env.PINATA_JWT }
    });
    await pinatino.initialize();

    const sql = withPinatino(neon(env.DATABASE_URL), {
      pinatino,
      strategy: 'write-behind'
    });

    const users = await sql`SELECT * FROM users LIMIT 10`;
    return new Response(JSON.stringify(users), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
};

Next.js API Route

// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';
import { PinatinoDB } from '@pinatinodb/core';

const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});

const sql = withPinatino(neon(process.env.DATABASE_URL!), {
  pinatino,
  logging: process.env.NODE_ENV === 'development'
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    const user = await sql`
      INSERT INTO users (name, email)
      VALUES (${req.body.name}, ${req.body.email})
      RETURNING *
    `;
    res.json(user[0]);
  } else {
    const users = await sql`SELECT * FROM users`;
    res.json(users);
  }
}

🎨 Advanced Patterns

Hybrid Query (Postgres + IPFS)

// Fast queries from Postgres
const recentUsers = await sql`
  SELECT * FROM users
  ORDER BY created_at DESC
  LIMIT 10
`;

// Historical queries from IPFS
const userCollection = pinatino.getCollection('users');
const allIPFSUsers = await userCollection.findAll();
console.log(`Total users in IPFS: ${allIPFSUsers.length}`);

Environment-Based Sync

const isDev = process.env.NODE_ENV === 'development';

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  strategy: isDev ? 'none' : 'write-behind',
  logging: isDev
});

Custom Error Handling

import * as Sentry from '@sentry/node';

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  onError: (error, operation, table) => {
    Sentry.captureException(error, {
      tags: { table, operation, adapter: 'neon' }
    });
  }
});

📊 Performance

Neon vs Traditional Postgres

| Feature | Traditional Postgres | Neon | | --------------- | -------------------- | ----------------- | | Cold Start | ~1-5s | ~0ms (instant) | | Scaling | Manual | Automatic | | Edge Deploy | ❌ | ✅ | | Cost | Fixed | Pay-per-use | | IPFS Sync | ✅ (with adapter) | ✅ (with adapter) | | Serverless | Limited | ✅ Optimized |

Query Performance

| Operation | Neon | + IPFS (write-through) | + IPFS (write-behind) | | ---------- | ----- | ---------------------- | --------------------- | | SELECT | ~5ms | ~5ms (no sync) | ~5ms (no sync) | | INSERT | ~10ms | ~60ms | ~10ms | | UPDATE | ~10ms | ~60ms | ~10ms | | DELETE | ~5ms | ~5ms | ~5ms |

Recommendation: Use write-behind for production (10ms latency instead of 60ms)

🔍 Querying

From Postgres (Fast)

// Indexed, fast queries
const users = await sql`
  SELECT * FROM users
  WHERE email = ${email}
  LIMIT 1
`;

From IPFS (Decentralized)

// Permanent, decentralized storage
const userCollection = pinatino.getCollection('users');
const ipfsUser = await userCollection.findById(userId);
console.log(`User CID: ${ipfsUser._cid}`);

Hybrid Fallback

async function getUser(id: string) {
  try {
    // Try Postgres first (fast)
    const result = await sql`SELECT * FROM users WHERE id = ${id}`;
    return result[0];
  } catch (error) {
    // Fallback to IPFS
    const collection = pinatino.getCollection('users');
    return await collection.findById(id);
  }
}

🎯 Best Practices

1. Use Write-Behind in Production

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  strategy: 'write-behind' // Fast, async sync
});

2. Selective Sync

// Only sync permanent data
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  tables: ['users', 'posts', 'products'],
  excludeTables: ['sessions', 'logs', 'cache']
});

3. Enable Connection Pooling

import { neonConfig } from '@neondatabase/serverless';

neonConfig.fetchConnectionCache = true;

4. Handle Errors Gracefully

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  onError: error => {
    // Postgres operation succeeds even if IPFS fails
    console.error('IPFS sync failed:', error);
  }
});

🚨 Limitations

  1. DELETE Operations: Cannot automatically sync deletes (need to query before delete)
  2. Complex Queries: Only basic INSERT/UPDATE/DELETE are auto-synced
  3. Bulk Operations: Large batch operations may be slow with write-through

🧪 Testing

// Disable IPFS sync in tests
const sql = withPinatino(neon(TEST_DATABASE_URL), {
  pinatino,
  strategy: 'none'
});

📚 More Examples

Check out the complete working example for serverless patterns.

🤝 Contributing

Found a bug? Open an issue!

📄 License

MIT


Made with ❤️ for serverless developers who want Web3 without complexity