superapp
BackendDatabases

PostgreSQL

Connect to PostgreSQL databases.

Attach a PostgreSQL database and get full CRUD through DuckDB's native postgres_scanner extension.

import { createEngine } from '@superapp/backend'
import { postgresProvider } from '@superapp/backend/integrations/postgres'

const engine = createEngine({
  integrations: [postgresProvider],
  connections: {
    main: { type: 'postgres', url: process.env.PG_URL! },
  },
})

Connection URL Format

Standard PostgreSQL connection string:

postgres://user:password@host:5432/database?sslmode=require
ParameterDescription
userDatabase user
passwordDatabase password
hostServer hostname or IP
5432Port (default: 5432)
databaseDatabase name
sslmodedisable, require, verify-ca, verify-full

What DuckDB Generates

When the engine starts, the Postgres provider generates:

INSTALL postgres;
LOAD postgres;
ATTACH 'postgres://user:password@host:5432/database' AS main (TYPE POSTGRES, READ_WRITE);

All tables in the target database become available under the main schema. DuckDB pushes filters, joins, and aggregations down to Postgres whenever possible.

Capabilities

OperationSupported
findMany / findOneYes
createYes
updateYes
deleteYes
count / aggregateYes
TransactionsYes

Full Example

import { createEngine } from '@superapp/backend'
import { postgresProvider } from '@superapp/backend/integrations/postgres'
import { betterAuthProvider } from '@superapp/backend/auth/better-auth'
import { createHonoMiddleware } from '@superapp/backend/adapters/hono'
import { Hono } from 'hono'
import { serve } from '@hono/node-server'

const engine = createEngine({
  integrations: [postgresProvider],
  connections: {
    main: { type: 'postgres', url: process.env.PG_URL! },
  },
  auth: betterAuthProvider({
    secret: process.env.AUTH_SECRET!,
    userTable: {
      table: 'main.users',
      matchOn: { column: 'id', jwtField: 'id' },
      columns: ['id', 'email', 'name'],
    },
  }),
  permissions: {
    read_orders: {
      name: 'Read orders',
      table: 'main.orders',
      operations: { select: true },
      columns: ['id', 'amount', 'status', 'customer_id', 'created_at'],
    },
  },
  roles: {
    viewer: ['read_orders'],
  },
})

const app = new Hono()
app.route('/', createHonoMiddleware(engine))
serve({ fetch: app.fetch, port: 3001 })

Multiple Postgres Connections

Attach several Postgres databases under different names:

const engine = createEngine({
  integrations: [postgresProvider],
  connections: {
    main: { type: 'postgres', url: process.env.PG_URL! },
    analytics: { type: 'postgres', url: process.env.ANALYTICS_PG_URL! },
  },
})

Tables are namespaced: main.orders, analytics.events.

Troubleshooting

ProblemCauseFix
Connection refusedPostgres not reachableCheck host, port, and firewall rules
password authentication failedWrong credentialsVerify user/password in connection URL
SSL connection requiredServer requires SSLAdd ?sslmode=require to the URL
relation does not existTable not in target databaseCheck database name in the URL
too many connectionsPool exhausted on Postgres sideIncrease max_connections or use a connection pooler like PgBouncer

On this page