Add persistence
You will add a PostgreSQL-backed feature using @putnami/sql with migrations and a repository.
Companion sample:
samples/ts/06-database— a runnable project with repository pattern, migrations, and transactions. Runbunx putnami serve @sample/ts-databasefrom the workspace root.
Steps
1) Add SQL + configure a database
bunx putnami deps add @putnami/sqlCreate .env.local.yaml:
database:
host: localhost
port: 5432
database: myapp
user: postgres
password: your_password2) Define a table + repository
Create apps/web/src/db/user.ts:
import { Table, Column, Key, Uuid, Email, Repository } from '@putnami/sql';
import type { InferTable } from '@putnami/sql';
const CreateUsersTable = {
name: '20250101000000-create-users-table',
sql: `
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL
);
`,
};
export const UsersTable = Table('users', {
id: Key(Uuid),
email: Column(Email),
name: Column(String),
}, {
migrations: [CreateUsersTable],
});
export type User = InferTable<typeof UsersTable>;
export class UserRepository extends Repository<typeof UsersTable> {
constructor() {
super(UsersTable);
}
}3) Enable the SQL plugin
Update apps/web/src/main.ts:
import { application } from '@putnami/application';
import { sql } from '@putnami/sql';
export const app = () => application().use(sql());4) Read and write from a route
Create apps/web/src/app/users/post.ts:
import { endpoint } from '@putnami/application';
import { UserRepository } from '../../db/user';
export default endpoint(async () => {
const repo = new UserRepository();
const user = await repo.save({
id: crypto.randomUUID(),
email: 'hello@example.com',
name: 'Hello',
});
return { user };
});Result
You now have an app that persists data.