Skip to content

Railway.Postgres reference

Source: src/Railway/ConnectPostgres.ts

Bind a Postgres database to a Railway Service or Function and obtain the Effect-native connection string for Drizzle.Postgres / SQL.Postgres.

ConnectPostgres is the Context tag, the type, and the callable — yield* Railway.ConnectPostgres(Db). Provide ConnectPostgresHttp.

import * as Drizzle from "alchemy/Drizzle/Postgres";
export default class Query extends Railway.Function<Query>()(
"Query",
{ project: Site, main: import.meta.url, build: { install: ["pg"] } },
Effect.gen(function* () {
const conn = yield* Railway.ConnectPostgres(Db);
const db = yield* Drizzle.Postgres(conn.connectionString);
return {
fetch: db.execute("select 1 as ok").pipe(
Effect.flatMap(HttpServerResponse.json),
),
};
}).pipe(Effect.provide(Railway.ConnectPostgresHttp)),
) {}

ConnectPostgres packs a typed private URI onto the host. To store Railway’s template instead of a resolved URI (IaC db.env.DATABASE_URL), pass Railway.ref(Db, "DATABASE_URL") as a Variable value or Service.env entry. Railway interpolates ${{Db.DATABASE_URL}} at build/runtime.

const db = yield* Railway.Postgres("Db", { project: site });
yield* Railway.Variable("DatabaseUrl", {
project: site,
service: api,
name: "DATABASE_URL",
value: Railway.ref(db, "DATABASE_URL"),
});

Source: src/Railway/ConnectPostgresHttp.ts Kind: Layer · Provides: Railway.ConnectPostgres

Implementation of ConnectPostgres. Provide it on the Service or Function Effect.

At deploy time this packs the private connection URI onto the host (RAILWAY_POSTGRES_*, DATABASE_URL). At runtime the client reads process.env.

Effect.gen(function* () {
const conn = yield* Railway.ConnectPostgres(Db);
const db = yield* Drizzle.Postgres(conn.connectionString);
}).pipe(Effect.provide(Railway.ConnectPostgresHttp))

Source: src/Railway/Postgres.ts

A Railway.Postgres is a Postgres-as-a-Service: the official ghcr.io/railwayapp-templates/postgres-ssl:16 image, a Volume at /var/lib/postgresql/data, POSTGRES_* / DATABASE_URL variables, and an optional TCP proxy for the public URL.

Private hostname is {name}.railway.internal. From a Service, yield ConnectPostgres. From a laptop, use publicConnectionUri.

Pass a Project. Alchemy generates a unique name, password, volume, and a public TCP proxy.

const site = yield* Railway.Project("Site");
const db = yield* Railway.Postgres("Db", { project: site });

Yield ConnectPostgres inside init. Provide ConnectPostgresHttp. Pass conn.connectionString to Drizzle.Postgres or SQL.Postgres. The binding packs the private URI ({name}.railway.internal).

import * as Drizzle from "alchemy/Drizzle/Postgres";
import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
export default class Api extends Railway.Service<Api>()(
"Api",
{ project: Site, main: import.meta.url, build: { install: ["pg"] } },
Effect.gen(function* () {
const conn = yield* Railway.ConnectPostgres(Db);
const db = yield* Drizzle.Postgres(conn.connectionString);
return {
fetch: Effect.gen(function* () {
const rows = yield* db.execute("select 1 as ok");
return HttpServerResponse.json({ rows });
}),
};
}).pipe(Effect.provide(Railway.ConnectPostgresHttp)),
) {}

public (default true) creates a TCP proxy on 5432. publicConnectionUri is {domain}:{proxyPort} for laptop access and deploy-time migrations.

const db = yield* Railway.Postgres("Db", {
project: site,
public: false,
});

Default is Postgres 16 with SSL. Pass image to pin another tag.

const db = yield* Railway.Postgres("Db", {
project: site,
image: "ghcr.io/railwayapp-templates/postgres-ssl:17",
});

Resource-valued props accept the resource or an Effect producing it.

src/db.ts
import * as Railway from "alchemy/Railway";
export const Site = Railway.Project("Site");
export const Db = Railway.Postgres("Db", { project: Site });